簡體   English   中英

正則表達式替換字符串中的所有\ n,但不包括[code] [/ code]標記內的所有\ n

[英]Regex to replace all \n in a String, but no those inside [code] [/code] tag

我需要幫助來替換所有\\ n(新行)的字符
在一個字符串中,但不是[code] [/ code]標簽內的那些\\ n。 我的大腦正在燃燒,我無法用自己解決這個問題:(

例:

test test test
test test test
test
test

[code]some
test
code
[/code]

more text

應該:

test test test<br />
test test test<br />
test<br />
test<br />
<br />
[code]some
test
code
[/code]<br />
<br />
more text<br />

謝謝你的時間。 最好的祝福。

我會建議一個(簡單的)解析器,而不是正則表達式。 像這樣的東西(糟糕的偽代碼):

stack elementStack;

foreach(char in string) {
    if(string-from-char == "[code]") {
        elementStack.push("code");
        string-from-char = "";
    }

    if(string-from-char == "[/code]") {
        elementStack.popTo("code");
        string-from-char = "";
    }

    if(char == "\n" && !elementStack.contains("code")) {
        char = "<br/>\n";
    }
}

你已經標記了正則表達式的問題,但這可能不是這項工作的最佳工具。

您可能更好地使用基本的編譯器構建技術(即lexer提供簡單的狀態機解析器)。

你的詞法分析器會識別五個標記:(“[code]”,“\\ n”,“[/ code]”,EOF,:所有其他字符串:)和你的狀態機看起來像:

state    token    action
------------------------
begin    :none:   --> out
out      [code]   OUTPUT(token), --> in
out      \n       OUTPUT(break), OUTPUT(token)
out      *        OUTPUT(token)
in       [/code]  OUTPUT(token), --> out
in       *        OUTPUT(token)
*        EOF      --> end

編輯:我看到其他海報討論嵌套塊的可能需要。 這個狀態機不會處理它。 對於嵌套塊,使用遞歸的正確解析器(不是那么簡單但仍然足夠容易和可擴展)。

編輯:Axeman指出,這種設計不允許在代碼中使用“[/ code]”。 可以使用逃逸機制來擊敗它。 像添加'\\'到你的標記並添加:

state    token    action
------------------------
in       \        -->esc-in
esc-in   *        OUTPUT(token), -->in
out      \        -->esc-out
esc-out  *        OUTPUT(token), -->out

到狀態機。

適用於機器生成的詞法分析器和解析器的通常參數適用。

這似乎是這樣做的:

private final static String PATTERN = "\\*+";

public static void main(String args[]) {
    Pattern p = Pattern.compile("(.*?)(\\[/?code\\])", Pattern.DOTALL);
    String s = "test 1 ** [code]test 2**blah[/code] test3 ** blah [code] test * 4 [code] test 5 * [/code] * test 6[/code] asdf **";
    Matcher m = p.matcher(s);
    StringBuffer sb = new StringBuffer(); // note: it has to be a StringBuffer not a StringBuilder because of the Pattern API
    int codeDepth = 0;
    while (m.find()) {
        if (codeDepth == 0) {
            m.appendReplacement(sb, m.group(1).replaceAll(PATTERN, ""));
        } else {
            m.appendReplacement(sb, m.group(1));
        }
        if (m.group(2).equals("[code]")) {
            codeDepth++;
        } else {
            codeDepth--;
        }
        sb.append(m.group(2));
    }
    if (codeDepth == 0) {
        StringBuffer sb2 = new StringBuffer();
        m.appendTail(sb2);
        sb.append(sb2.toString().replaceAll(PATTERN, ""));
    } else {
        m.appendTail(sb);
    }
    System.out.printf("Original: %s%n", s);
    System.out.printf("Processed: %s%n", sb);
}

它不是一個簡單的正則表達式,但我不認為你可以用一個簡單的正則表達式做你想要的。 不處理嵌套元素等等。

正如其他海報所提到的,正則表達式不是這項工作的最佳工具,因為它們幾乎普遍被實現為貪婪算法。 這意味着即使您嘗試使用以下內容匹配代碼塊:

(\[code\].*\[/code\])

然后表達式將匹配從第一個[code]標簽到最后一個[/code]標簽的所有內容,這顯然不是您想要的。 雖然有辦法解決這個問題,但是由此產生的正則表達式通常很脆弱,不直觀,而且非常丑陋。 類似下面的python代碼會更好。

output = []
def add_brs(str):
    return str.replace('\n','<br/>\n')
# the first block will *not* have a matching [/code] tag
blocks = input.split('[code]')
output.push(add_brs(blocks[0]))
# for all the rest of the blocks, only add <br/> tags to
# the segment after the [/code] segment
for block in blocks[1:]:
    if len(block.split('[/code]'))!=1:
        raise ParseException('Too many or few [/code] tags')
    else:
        # the segment in the code block is pre, everything
        # after is post
        pre, post = block.split('[/code]')
        output.push(pre)
        output.push(add_brs(post))
# finally join all the processed segments together
output = "".join(output)

請注意,上面的代碼沒有經過測試,只是粗略了解您需要做什么。

為了做到這一點,你真的需要做三次通過:

  1. 找到[code]塊並用唯一的令牌+索引替換它們(保存原始塊),例如“foo [code] abc [/ code] bar [code] efg [/ code]”變成“foo TOKEN-1 barTOKEN -2"
  2. 做換行換刀。
  3. 掃描轉義令牌並恢復原始塊。

代碼看起來像*:

Matcher m = escapePattern.matcher(input);
while(m.find()) {
    String key = nextKey();
    escaped.put(key,m.group());
    m.appendReplacement(output1,"TOKEN-"+key);
}
m.appendTail(output1);
Matcher m2 = newlinePatten.matcher(output1);
while(m2.find()) {
    m.appendReplacement(output2,newlineReplacement);
}
m2.appendTail(output2);
Matcher m3 = Pattern.compile("TOKEN-(\\d+)").matcher(output2); 
while(m3.find()) {
    m.appendReplacement(finalOutput,escaped.get(m3.group(1)));
}
m.appendTail(finalOutput);

這是快速而骯臟的方式。 有更有效的方法(其他人提到了解析器/詞法分析器),但除非你處理數百萬行並且你的代碼是CPU綁定的(而不是像大多數webapps那樣受I / O約束)並且你已經通過分析器確認了這是瓶頸,他們可能不值得。

*我沒有運行它,這完全來自內存。 只需檢查API ,您就可以解決它。

這很難,因為如果正則表達式善於發現某些東西,那么除了某些東西之外,它們並不擅長匹配所有東西......所以你必須使用循環,我懷疑你可以一次性做到這一點。

搜索之后,我發現了cletus解決方案的一些內容,除了我認為代碼塊不能嵌套,導致更簡單的代碼:選擇適合您需求的代碼。

import java.util.regex.*;

class Test
{
  static final String testString = "foo\nbar\n[code]\nprint'';\nprint{'c'};\n[/code]\nbar\nfoo";
  static final String replaceString = "<br>\n";
  public static void main(String args[])
  {
    Pattern p = Pattern.compile("(.+?)(\\[code\\].*?\\[/code\\])?", Pattern.DOTALL);
    Matcher m = p.matcher(testString);
    StringBuilder result = new StringBuilder();
    while (m.find()) 
    {
      result.append(m.group(1).replaceAll("\\n", replaceString));
      if (m.group(2) != null)
      {
        result.append(m.group(2));
      }
    }
    System.out.println(result.toString());
  }
}

粗略快速測試,你需要更多(null,空字符串,無代碼標簽,多個等)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM