正则表达式IF THEN ELSE语句

12

我需要编写一个正则表达式,这让我很困惑。基本上,我有一列包含如下数值的数据:

ACME Corp 123
Corp 742 ACME
Random Text
Broadway 1785 FB

我想要做的是查找术语ACMEBROADWAY。如果两者都存在,则只保留它们。如果两者都不存在,则保留整个字符串。因此,该列将变为:

ACME
ACME
Random Text
Broadway

那样说你明白了吗?


你是否在使用正则表达式时遇到了困难?除了像Python这样的解析工具,还有其他更简单的替代方案吗? - aphrid
如果你使用ifelifelse语句,而不是正则表达式,那么这将会更容易。你需要使用纯正则表达式的特定原因是什么?你的代码是用哪种语言编写的? - Davy M
如果你有一个实体列表(在你的情况下,看起来是公司),想要提取出来,为什么不简单地检查它们是否存在于字符串中呢?比如像这样if 'ACME' in 'ACME Corp 123'... - blacksite
1
我可以很容易地在SQL中使用CASE语句来完成这个任务,只需要5秒钟。然而,我正在使用的这个工具集限制了我只能使用正则表达式。 - Domo Dan
1
纳什维尔的人,是吗? - papelr
4个回答

24

简述

这个问题曾经让我感到困惑。我相信仅使用正则表达式并不是解决这个问题的最佳方法,但以下是解决方案。


代码

在此处查看该代码的使用情况

正则表达式

^.*?((?(?=.*?(\b(?:broadway|acme)\b).*?)\2|.*)).*?$

替换

下面是第一个分组。您可以从匹配数组中收集第一个分组变量,但如果想要替换,可以使用以下方法。

$1

结果

注意:我添加了另一个字符串作为测试,以确保如果任一单词放在行中间,它仍然能够捕获。

输入

ACME Corp 123
Corp 742 ACME
Some ACME some
Random Text
Broadway 1785 FB

输出

ACME
ACME
ACME
Random Text
Broadway

说明

使用不区分大小写的标记i和多行标记m

  • ^断言位于行的开头
  • .*?匹配任意数量的任意字符,但尽可能少地匹配
  • ((?(?=.*?(\b(?:broadway|acme)\b).*?)\2|.*))分解成以下部分
    • ()捕获以下内容
      • (?(?=...))if/else语句
      • (?=.*?(\b(?:broadway|acme)\b).*?)正向先行断言以匹配以下内容
        • .*?任意数量的任意字符,但尽可能少地匹配
        • (...)将以下内容捕获到捕获组2中
        • \b(?:broadway|acme)\b单词边界,后跟broadwayacme,再后跟单词边界
        • .*?任意数量的任意字符,但尽可能少地匹配
      • \2如果if / else语句为true(它匹配上述内容),则捕获该组(如上所述)-即只有broadwayacme
      • .*如果if/else语句为false,则匹配任意数量的任意字符
  • .*?匹配任意数量的任意字符,但尽可能少地匹配
  • $断言位于行的结尾

—-

更新

由于我的答案引起了相当多的关注,我想我应该修改一下。不确定关注的是正则表达式中的if / else还是与OP的样本输入相关。

if/else

我应该提到正则表达式if/else的一般格式如下(仅某些正则表达式引擎支持此标记):

(?(?=condition)x|y)
在上面的正则表达式中,(?=condition) 可以是任何你想要的东西(你也可以使用负向先行断言或后行断言,甚至是它们的组合。

替代方案

由于正则表达式中的if/else并不支持所有语言,您可能需要使用一些变通方法:

# optional group, fallback to match all (x?y)
^(?:.*?\b(broadway|acme)\b)?.*

# alternation (x||y)
^(?:.*?\b(broadway|acme)\b|.*)

# tempered greedy token alternation
^(?:(?!\b(?:broadway|acme)\b).|(broadway|acme))+

# same as above reusing capture group 1’s definition 
^(?:(?!\b(broadway|acme)\b).|((?1)))+

3
美妙的方法。很高兴知道有人可以教我们一些技巧。 :) - wp78de

4
一个可以解决这个问题的正则表达式是:
 ^(?(?=(acme|broadway))\1|[\w\s])+?$

为什么这样就足够了呢?如果你的输入字符串中包含acme或者broadway,那么第一组将会捕获这个值。如果第一组为空,则完整匹配就是你的结果。

分解:

 ^(?                          # start conditional
    (?=                       # lookahead for position before
      (                       # group 1 start
        acme|broadway         # either "acme" or "broadway"
      )                       # group 1 end
    )
    \1                        # if found, then match group 1
    |                         # else
    [\w\s]                    # read a word char or space
  )+?$                        # do this over and over again, non-greedy 

请查看示例1

1
不是。仔细看看。或者看看这个链接:https://regex101.com/r/6KZ81f/3 - Marc Lambrichs
你的正则表达式似乎无效。 - Alexandru R
1
可以再提供一些上下文吗?如果您认为正则表达式无效,我建议检查链接。如果您的陈述是“这并没有回答OP的问题”,请解释您的想法。 - Marc Lambrichs

2

不使用前瞻断言的另一种解决方案

^.*(ACME|Broadway).*$

说明:

^                     # beginning of the string
 .*                   # match any character any number of times
   (                  # start of capture group
    ACME|Broadway     # if the input string has ACME or Broadway capture in the memory($1)
   )                  # end of the capture group
 .*                   # match any character any number of times
$                     # end of the string

https://regex101.com/r/mDCL5g/1

此外,您可以在Javascript中使用相同的正则表达式,如下所示

'ACME Corp 123'.replace(/^.*(ACME|Broadway).*$/, '$1');    // ACME
'Corp 742 ACME'.replace(/^.*(ACME|Broadway).*$/, '$1');    // ACME
'Random Text'.replace(/^.*(ACME|Broadway).*$/, '$1');      // Random Text
'Broadway 1785 FB'.replace(/^.*(ACME|Broadway).*$/, '$1'); // Broadway 

1
这里是另一次尝试:
(?:^.*)(ACME)(?:.*$)?|(?:^.*)(Broadway)(?:.*$)|^.*$

并且正则表达式正在使用的代码

这个解决方案与Marc Lambrichs的解决方案相似,但使用了两个捕获组(这可能更糟糕——但这取决于您的需求)。如果两个组中没有一个匹配,您将在完整匹配中找到随机文本。

如果您不喜欢第二个捕获组,可以尝试这个:

(?:^.*?)(ACME|Broadway)(?:.*$)?|^.*?$

或者,如果您想像ctwheels的解决方案一样将所有内容放在$1中:

(?(?=(?:^.*?)?(ACME|Broadway)(?:.*$)?)\1|(^.*?$))

正如Marc指出的那样,我的方法的优点在于它不需要高级功能,这些功能并非所有正则表达式引擎都支持。
然而,作为第三个正则表达式中使用的条件正则表达式并不是到处都可用的。

是的,情况变得更糟了。因为现在你必须检查第一组和第二组,才能知道是否没有匹配。在所有情况下都是如此。 - Marc Lambrichs
正如我所说,虽然我本可以进行调整,但由于我们没有收到原始问题提出者的回应,我觉得这样做是没有意义的。 - wp78de

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接