Java Regex替换字符串中的所有\n,但不替换[code][/code]标记中的所有
我需要帮助来替换字符串中Java Regex替换字符串中的所有\n,但不替换[code][/code]标记中的所有,java,regex,Java,Regex,我需要帮助来替换字符串中的所有\n(新行)字符,而不是[code][/code]标记中的那些字符。 我的大脑在燃烧,我自己解决不了这个问题:( 例如: 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 />
的所有\n(新行)字符,而不是[code][/code]标记中的那些字符。 我的大脑在燃烧,我自己解决不了这个问题:( 例如:
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 />
测试
测试测试
测试
测试
[代码]一些
测试
代码
[/code]
更多文本
谢谢你抽出时间。
致以最诚挚的问候。我建议使用(简单的)解析器,而不是正则表达式。类似这样的东西(错误的伪代码):
stack元素栈;
foreach(字符串中的字符){
if(字符中的字符串=“[代码]”){
elementStack.push(“代码”);
字符串from char=“”;
}
if(字符中的字符串==“[/code]”){
elementStack.popTo(“代码”);
字符串from char=“”;
}
if(char==“\n”&&&!elementStack.contains(“代码”)){
char=“
\n”;
}
}
您已经标记了问题正则表达式,但这可能不是执行此任务的最佳工具
使用基本的编译器构建技术(例如,一个lexer提供一个简单的状态机解析器)可能会更好
您的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
状态令牌操作
------------------------
开始:无:-->输出
out[代码]输出(令牌),-->in
输出\n输出(中断)、输出(令牌)
输出*输出(令牌)
输入[/code]输出(令牌),-->输出
in*输出(令牌)
*EOF-->结束
编辑:我看到另一张海报讨论了嵌套块的可能需要。这个状态机不会处理这个问题。对于嵌套块,使用一个递归的像样的解析器(不是很简单,但仍然足够简单和可扩展)
编辑:Axeman指出,这种设计不允许在代码中使用“[/code]”。可以使用转义机制来解决这个问题。类似于将“\”添加到您的令牌并添加:
state token action
------------------------
in \ -->esc-in
esc-in * OUTPUT(token), -->in
out \ -->esc-out
esc-out * OUTPUT(token), -->out
状态令牌操作
------------------------
in \-->esc in
esc in*输出(令牌),-->in
退出\-->退出
esc输出*输出(令牌),-->输出
到状态机
支持机器生成的词法分析器和语法分析器的常用参数适用。要正确使用,您确实需要做三个步骤:
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限制(而不是像大多数Web应用一样受I/O限制),并且你已经用分析器确认这是瓶颈,否则它们可能不值得
*我没有运行它,这都是从内存中获得的。只需检查,您就可以计算出来。正如其他海报所提到的,正则表达式不是这项工作的最佳工具,因为它们几乎被普遍实现为贪婪算法。这意味着,即使您尝试使用以下方法匹配代码块:
(\[code\].*\[/code\])
然后表达式将匹配从第一个[code]
标记到最后一个[/code]标记的所有内容
tag,这显然不是您想要的。虽然有一些方法可以解决这个问题,但得到的正则表达式通常是脆弱的、不直观的,而且非常难看。类似于下面的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)
output=[]
def添加brs(str):
返回str.replace('\n','
\n')
#第一个块*没有*匹配的[/code]标记
blocks=input.split(“[code]”)
push(添加br(块[0]))
#对于所有其余的块,只需将
标记添加到
#[/code]段后的段
对于块中的块[1:]:
如果len(block.split('[/code]')!=1:
raise ParseException('太多或太少[/code]标记')
其他:
#代码块中的段是pre,所有
#之后是邮政
pre,post=block.split(“[/code]”)
输出。推送(预)
输出推送(添加brs(post))
#最后将所有处理过的段连接在一起
output=”“.join(输出)
请注意,上面的代码没有经过测试,只是大致了解您需要做什么。这似乎可以做到:
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);
}
这不是一个简单的正则表达式,但我认为你不能用一个简单的正则表达式做你想做的事情。不能处理嵌套元素等等。这很难,因为如果正则表达式善于发现某些东西,它们就不太擅长匹配除某些东西以外的所有东西……所以你必须使用循环,我怀疑你能否一次性做到这一点。 搜索之后,我发现了一些与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());
}
}
import java.util.regex.*;
课堂测试
{
静态最终字符串testString=“foo\nbar\n[code]\nprit”“;\nprit{'c'};\n[/code]\nbar\nfoo”;
静态最终字符串replaceString=“
\n”;
公共静态void main(字符串参数[])
{
Pattern p=Pattern.compile((.+?)(\\[code\\].\\[/code\\])?”,Pattern.DOTALL);
Matcher m=p.Matcher(testString);
StringBuilder结果=新建StringBuilder();
while(m.find())
{
result.append(m.group(1.replaceAll)(\\n,replaceString));
如果(m.group(2)!=null)
{
结果:追加(m组(2));
}
}
System.out.println(result.toString());
}
}
粗略的快速测试,您需要更多(null、空字符串、无代码标记、多个等)。对于这个用例,显然不会有嵌套的[code]块,因此不情愿的量词会处理这个问题。例如,“[code].*?[\\code]”将在遇到“[/code]”时立即停止
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());
}
}