[英]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)
請注意,上面的代碼沒有經過測試,只是粗略了解您需要做什么。
為了做到這一點,你真的需要做三次通過:
代碼看起來像*:
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.