我需要编写替换a
为b
但仅在<pre>
标签内的正则表达式。
例子
a <pre> c a <foo> a d </pre> a
结果
a <pre> c b <foo> b d </pre> a
请帮助编写javaString.replace
函数的表达式。保证pre
标签没有嵌套。
我认为你可以用 String.replace() 做的最好的事情是:
String string = ...
for (;;)
{
String original = string;
string = string.replaceFirst("(<pre>.*?)a(.*?</pre>)", "$1b$2");
if (original.equals(string))
break;
}
(编辑:@Bohemian 已经注意到上述正则表达式无法正常工作。因此需要将其更改为:(
(<pre>(?:(?!</pre>).)*a((?:(?!<pre>).)*</pre>)
未经测试)以避免在部分之外匹配<pre>...</pre>
。通过此更改,我们不需要*?
量词并且可以使用更多常见的“贪婪”(*
)量词。这开始看起来很像我的其他答案,我只是开玩笑!)
你最好使用匹配器(按照我脑海中的代码):
import java.util.regex.Pattern;
import java.util.regex.Matcher;
Pattern pattern = Pattern.compile("(?<=<pre>)(.*?)(?=</pre>)");
Matcher m = pattern.matcher(string);
StringBuffer replacement = new StringBuffer();
while (matcher.find())
{
matcher.appendReplacement(replacement, "");
// Careful using unknown text in appendReplacement as any "$n" will cause problems
replacement.append(matcher.group(1).replace("a", "b"));
}
matcher.appendTail(replacement);
String result = replacement.toString();
编辑:更改了上面的模式,使其与周围<pre>
的 and不匹配</pre>
。
这是一个可以完成这项工作的正则表达式(我认为:我不会在它通过所有测试方面下太多赌注)
String replacement = original.replaceAll(
"(?<=<pre>(?:(?!</pre>).){0,50})a(?=(?:(?!<pre>).)*</pre>)",
"b");
解释:
(?<=<pre>(?:(?!</pre>).){0,50})
-
<pre>
只要我们不回头</pre>
找到它,就向后看。Java 需要有限的最大长度后视,所以我们使用{0,50}
而不是*
.a
- 我们要替换的字符(?=(?:.(?!<pre>))*</pre>)
- 向前看,</pre>
只要我们不穿越过去<pre>
就可以找到它。Pattern pattern = Pattern.compile("<pre>(.+?)</pre>");
java.util.regex.Matcher matcher = pattern.matcher("a <pre> c a <tag> a d </pre> a");
试试这个: