代码之家  ›  专栏  ›  技术社区  ›  Alexey Romanov

一次替换两个正则表达式

  •  1
  • Alexey Romanov  · 技术社区  · 15 年前

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

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

    但是,假设 myString 可能很长,所以最好避免两次传球。这可以一次性完成吗?

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

    显然是 pattern pattern1 + "|" + pattern2 但是我不知道怎么写 replacement .

    为了简化,我们假设 pattern1 pattern2 不能相交,那 replacement1 不引入任何新的匹配项 图案化2 .

    4 回复  |  直到 15 年前
        1
  •  1
  •   tchrist    15 年前

    最简单的方法是维护将字符串映射到替换字符串的哈希。组成匹配任何键的匹配项,并将匹配的键传递给替换部分。替换部分要比拉入值多。

    在Perl中,这仅仅是:

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

    等价的Java解决方案会像所有的东西一样长得多,但是同样的方法也会起作用。

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

        2
  •  1
  •   Florian    15 年前

    根据您使用的编程语言的实际情况,您可以使用回调作为替换,并使用与这两种语言都匹配的regexp,然后在回调函数中有一个if语句,该语句检查regexp是否匹配,并将其替换为适当的替换。

        3
  •  1
  •   Community Mohan Dere    8 年前

    与几乎所有其他正则表达式不同,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;
      }
    }
    
        4
  •  0
  •   davidkovsky    15 年前

    正如@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在字符串s中看到“hello”或“world”时,它会将该值发送到名为match的变量中的块。该块将“您好”替换为“您好!”,并将任何其他值替换为“Universe!”