使用正则表达式在文本python中使用缩写的第一个字母匹配相邻单词

2024-05-15 13:46:00 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个缩略语列表,我试图在我的文本中找到使用正则表达式。然而,我正在努力通过匹配字母来找到相邻的单词,并且只有通过单词匹配才能做到这一点。这是我的文本

text = '''They posted out the United States Navy Seals (USNS) to the area.
Entrance was through an underground facility (UGF) as they has to bypass a no-fly-zone (NFZ).
I found an assault-rifle (AR) in the armoury.'''

我的清单如下:[USNS, UGF, NFZ, AR]

我想用每个缩写的第一个字母在文本中找到相应的长格式。它还需要不区分大小写。到目前为止,我的尝试是:

re.search(r'\bUnited\W+?States\b\W+?Navy\b\W+?Seals\b', text) 但当我尝试使用第一个字母时,返回美国海军海豹突击队:

re.search(r'\bU\W+?S\b\W+?N\b\W+?S\b', text)

然后它什么也不返回。此外,有些缩略语在文本中包含的内容超过了单词的首字母,例如UGF-地下设施

我的实际目标是最终用相应的长格式(美国海军海豹突击队地下设施禁飞区突击步枪)替换文本中的所有缩写(美国海军海豹突击队地下设施禁飞区突击步枪


Tags: thetotext文本字母单词突击队海军
2条回答

在上一个正则表达式中[1]

re.search(r'\bU\W+?S\b\W+?N\b\W+?S\b', text)

你没有对手,因为你犯了几个错误:

  • \w+表示一个或多个单词字符,\W+表示一个或多个非单词字符
  • 有时\b边界锚点位于错误的位置(即,在首字母和单词的其余部分之间)
re.search(r'\bU\w+\sS\w+?\sN\w+?\sS\w+', text)

应该匹配

而且呢,

print(re.search(r'\bu\w+?g\w+\sf\w+', text))

当然匹配underground facility但是在长文本中,会有更多不相关的匹配

推广方法

最后,我构建了一个小“机器”,它可以根据已知的缩写动态创建正则表达式:

import re

text = '''They posted out the United States Navy Seals (USNS) to the area.
Entrance was through an underground facility (UGF) as they has to bypass a no-fly-zone (NFZ).
I found an assault-rifle (AR) in the armoury.'''

abbrs = ['USNS', 'UGF', 'NFZ', 'AR']

for abbr in abbrs:
    pattern = ''.join(map(lambda i: '['+i.upper()+i.lower()+'][a-z]+[ a-z-]', abbr))
    print(pattern) 
    print(re.search(pattern, text, flags=re.IGNORECASE)) 

上述脚本的输出为:

[Uu][a-z]+[ a-z-][Ss][a-z]+[ a-z-][Nn][a-z]+[ a-z-][Ss][a-z]+[ a-z-]
<re.Match object; span=(20, 45), match='United States Navy Seals '>
[Uu][a-z]+[ a-z-][Gg][a-z]+[ a-z-][Ff][a-z]+[ a-z-]
<re.Match object; span=(89, 110), match='underground facility '>
[Nn][a-z]+[ a-z-][Ff][a-z]+[ a-z-][Zz][a-z]+[ a-z-]
<re.Match object; span=(140, 152), match='no-fly-zone '>
[Aa][a-z]+[ a-z-][Rr][a-z]+[ a-z-]
<re.Match object; span=(170, 184), match='assault-rifle '>

进一步推广

如果我们假设在文本中,每个缩写都是在第一次出现相应的长格式之后引入的,并且我们进一步假设它的书写方式肯定以单词边界开始,肯定以单词边界结束(没有关于大写和连字符使用的假设),我们可以尝试自动提取术语表,如下所示:

import re

text = '''They posted out the United States Navy Seals (USNS) to the area.
Entrance was through an underground facility (UGF) as they has to bypass a no-fly-zone (NFZ).
I found an assault-rifle (AR) in the armoury.'''

# build a regex for an initial
def init_re(i):
    return f'[{i.upper()+i.lower()}][a-z]+[ -]??'

# build a regex for an abbreviation
def abbr_re(abbr):
    return r'\b'+''.join([init_re(i) for i in abbr])+r'\b'

# build an inverse glossary from a text
def inverse_glossary(text):
    abbreviations = set(re.findall('\([A-Z]+\)', text))
    igloss = dict()
    for pabbr in abbreviations:
        abbr = pabbr[1:-1]
        pattern = '('+abbr_re(abbr)+') '+r'\('+abbr+r'\)'
        m = re.search(pattern, text)
        if m:
            longform = m.group(1)
            igloss[longform] = abbr
    return igloss

igloss = inverse_glossary(text)
for long in igloss:
    print('{} -> {}'.format(long, igloss[long]))

输出是

no-fly-zone -> NFZ
United States Navy Seals -> USNS
assault-rifle -> AR
underground facility -> UGF

通过使用反向词汇表,您可以轻松地将所有长格式替换为相应的缩写。除了第一次发生之外,所有的事情都有点难。有很大的细化空间,例如正确处理长表单中的换行符(也可以使用re.compile

要用长形式替换缩写,您必须构建一个标准词汇表,而不是相反的词汇表:

# build a glossary from a text
def glossary(text):
    abbreviations = set(re.findall('\([A-Z]+\)', text))
    gloss = dict()
    for pabbr in abbreviations:
        abbr = pabbr[1:-1]
        pattern = '('+abbr_re(abbr)+') '+r'\('+abbr+r'\)'
        m = re.search(pattern, text)
        if m:
            longform = m.group(1)
            gloss[abbr] = longform
    return gloss

gloss = glossary(text)
for abbr in gloss:
    print('{}: {}'.format(abbr, gloss[abbr]))

这里的输出是

AR: assault-rifle
NFZ: no-fly-zone
UGF: underground facility
USNS: United States Navy Seals

{a2}本身留给读者


[1] 让我们再仔细看看你的第一个正则表达式:

re.search(r'\bUnited\W+?States\b\W+?Navy\b\W+?Seals\b', text)

边界锚(\b)是冗余的。可以在不更改结果中任何内容的情况下删除它们,因为\W+?表示在StatesNavy的最后一个字符之后至少有一个非单词字符。它们在这里不会引起任何问题,但我想,当您开始修改它以获得更通用的版本时,它们导致了混乱

您可以使用下面的正则表达式,它也可以考虑区分大小写。单击here

这只会找到美国海军海豹突击队

\s[u|U].*?[s|S].*?[n|N].*?[s|S]\w+

同样,对于UF, 您可以使用-\s[u|U].*?[g|G].*?[f|F]\w+

请在上面找到一个图案。字符仅与.*?连接,每个字符用作[a|A],它将匹配小写或大写。开头应该是\s,因为它应该是一个单词,结尾应该是\w+

到处玩

相关问题 更多 >