【问题标题】:how to match abbreviations with their meaning with regex?如何使用正则表达式将缩写与其含义相匹配?
【发布时间】:2020-12-17 06:00:08
【问题描述】:

我正在寻找与以下字符串匹配的正则表达式模式:

一些示例文本 (SET) 展示了我正在寻找的内容。能源系统模型 (ESM) 用于寻找特定的最优值 (SCO)。有人说计算机系统 (CUST) 很酷。夏天在外面玩(OUTS)应该是首选。

我的目标是匹配以下内容:

Some example text (SET)
Energy system models (ESM)
specific optima (SCO)
computer systems (CUST)
outside (OUTS)

重要的是,它并不总是正好是三个单词和它们的第一个字母。有时用于缩写的字母仅包含在前面的单词中。这就是我开始研究positive lookbehind 的原因。但是,它受到长度的限制,可以通过将其与positive lookahead 组合来解决。到目前为止,我还没有想出一个可靠的解决方案。

到目前为止我所做的尝试:

(\b[\w -]+?)\((([A-Z])(?<=(?=.*?\3))(?:[A-Z]){1,4})\)

这很有效,但匹配包含的单词太多:

Some example text (SET)
Energy system models (ESM)
are used to find specific optima (SCO)
Some say Computer systems (CUST)
In the summer playing outside (OUTS)

我还尝试在第一组的开头使用对缩写首字母的引用。但这根本不起作用。

我看过但没有发现有用的东西:

有用的资源:

【问题讨论】:

  • 括号之间的大写字符连接到它前面的单词没有逻辑吗?
  • 试试[x.group() for x in re.finditer(r'\b([A-Z])\w*(?:\s+\w+)*?\s*\(\1[A-Z]*\)', text)] (regex demo)
  • @Thefourthbird 逻辑是它事先如何缩写单词,因此大写字符必须包含在其中。
  • 啊,一定是[x.group() for x in re.finditer(r'\b([A-Z])\w*(?:\s+\w+)*?\s*\(\1[A-Z]*\)', text, re.I)]Python demo)。我不确定是否只检查第一个单词的首字母是否适合 OP。 @david,够不够好,还是你认为一定有更复杂的逻辑?
  • @WiktorStribiżew 这似乎不太正确,因为缩写应该全部大写。否则,可能会出现误报,例如:Stupid example(s)

标签: python regex regex-lookarounds


【解决方案1】:

我建议使用

import re
def contains_abbrev(abbrev, text):
    text = text.lower()
    if not abbrev.isupper():
        return False
    cnt = 0
    for c in abbrev.lower():
        if text.find(c) > -1:
            text = text[text.find(c):]
            cnt += 1
            continue
    return cnt == len(abbrev)
 
text= "Some example text (SET) that demonstrates what I'm looking for. Energy system models (ESM) are used to find specific optima (SCO). Some say computer systems (CUST) are cool. In the summer playing outside (OUTS) should be preferred. Stupid example(s) Stupid example(S) Not stupid example (NSEMPLE), bad example (Bexle)"
abbrev_rx = r'\b(([A-Z])\w*(?:\s+\w+)*?)\s*\((\2[A-Z]*)\)'
print( [x.group() for x in re.finditer(abbrev_rx, text, re.I) if contains_abbrev(x.group(3), x.group(1))] )

请参阅Python demo

使用的正则表达式是

(?i)\b(([A-Z])\w*(?:\s+\w+)*?)\s*\((\2[A-Z]*)\)

请参阅regex demo。详情:

  • \b - 字边界
  • (([A-Z])\w*(?:\s+\w+)*?) - 第 1 组 (text):一个 ASCII 字母被捕获到第 2 组中,然后是 0+ 个单词字符,后跟任意 0 次或多次出现的 1+ 个空格,后跟 1+ 个单词字符,尽可能少
  • \s* - 0+ 个空格
  • \( - 一个 ( 字符
  • (\2[A-Z]*) - 第 3 组 (abbrev):与第 2 组中的值相同,然后是 0 个或多个 ASCII 字母
  • \) - ) 字符。

一旦匹配,第 3 组作为 abbrev 传递,第 1 组作为 text 传递给 contains_abbrev(abbrev, text) 方法,确保 abbrev 是大写字符串,并且 @ 中的字符987654339@ 与text 中的顺序相同,并且都出现在text 中。

【讨论】:

  • contains_abbrev 中的text 应转换为小写,并且正则表达式的缩写部分应具有固定长度{2,}。通过这些更改,它可以按预期工作。
  • @david 不需要小写,re.I 使模式不区分大小写。如果您需要确保缩写中至少有 2 个字符,请将 \2[A-Z]* 替换为 \2[A-Z]+
  • 需要小写,因为用于比较的文本不一定是小写。因此,到目前为止,您的代码对于第一个缩写词都失败了。
  • @david 我明白你的意思了。我添加了text 小写行。
【解决方案2】:

仅仅正则表达式是不够的......看起来你可能会为此编写一个 python 脚本...... 这应该可以处理您的所有场景:

import re
a="Some example text (SET) that demonstrates what I'm looking for. Energy system models (ESM) are used to find specific optima (SCO). Some say computer systems (CUST) are cool. In the summer playing outside (OUTS) should be preferred.";
b=re.findall("(\((.*?)\))",a)
a=a.replace(".","")
i=a.split(' ')
for c in b:
   cont=0
   m=[]
   s=i.index(c[0])
   l=len(c[1])
   al=s-l
   for j in range(al,s+1):
       if i[j][0].lower() == c[1][0].lower():
            cont=1
       if cont == 1:
            m.append(i[j])
   print(' '.join(m))

输出:

一些示例文本(SET)

能源系统模型 (ESM)

特定最优值 (SCO)

计算机系统 (CUST)

外(OUTS)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-16
    • 2012-01-16
    • 2014-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多