一次取代两个正则表达式

时间:2010-10-28 18:06:51

标签: regex

我想在一个字符串上进行两次正则表达式替换,即用Java术语

myString.replaceAll(pattern1, replacement1).replaceAll(pattern2, replacement2);

但是,假设myString可能很长,所以最好避免对它进行两次传递。这可以单程完成吗?

String pattern = ...;
String replacement = ...;
myString.replaceAll(pattern, replacement);

pattern的明显候选人是pattern1 + "|" + pattern2,但后来我看不到如何撰写replacement

为了简化,我们假设pattern1pattern2的匹配不能相交,replacement1不会引入pattern2的任何新匹配。

4 个答案:

答案 0 :(得分:1)

根据您使用的编程语言这一事实​​,您可以使用回调作为替换,并使用与两者匹配的RegExp,然后您将在回调函数中使用if语句检查匹配和替换的regexp它有适当的替代品。

答案 1 :(得分:1)

执行此操作的最简单方法是维护将字符串映射到其替换项的哈希。编写匹配任何键的匹配项,并将匹配的键传递给替换部分。有替换部分而不是拉入值。

在Perl中,这只会是:

my @keys = keys %hash;
my $alt = '\b(' . join("|", @keys) . ')\b';
s/($alt)/$hash{$1}/g;

等效的Java解决方案 - 就像所有东西一样 - 显着更长,但同样的方法也可以。

如果一个字符串是另一个字符串的起始子字符串,则会出现排序问题。

答案 2 :(得分:1)

与几乎所有其他正则表达式不同,Java不支持回调。但是,它确实暴露了一些允许您自己实现它们的低级API调用。这是一篇文章,展示了如何做到这一点:

Java Regex Replace with Capturing Group

正如您所指出的,您需要将模式合并为一个,但您还需要在其自己的捕获组中隔离每个模式,如下所示:

String bigPattern = "(" + pattern1 + ")|(" + pattern2 + ")";

(如果模式已经包含捕获组,这将改变编号方案;您将必须调整任何反向引用。我将假设除了您刚创建的那些之外没有捕获组。)

然后,在replacement()方法中,您确定实际匹配的组,并相应地选择替换文本:

public String replacement()
{
  if (group(1) != null)
  {
    return replacement1;
  }
  else if (group(2) != null)
  {
    return replacement2;
  }
}

答案 3 :(得分:0)

正如@levu所说,这取决于编程语言。在Ruby中,你可以这样做:

ree-1.8.7-2010.02 > s
 => "hello world" 
ree-1.8.7-2010.02 > s.gsub(/(hello|world)/) {|match| match == 'hello' ? 'hi there!' : 'universe!' }
 => "hi there! universe!" 

当gsub在String中看到“hello”或“world”时,它会将该值发送到名为match的变量中的块。该块用“hi there!”替换“hello”,并用“universe!”替换任何其他值。