Использование регулярного выражения для сопоставления соседних слов с использованием первой буквы сокращений в тексте python - PullRequest
0 голосов
/ 09 мая 2020

У меня есть список сокращений, которые я пытаюсь найти в своем тексте с помощью регулярного выражения. Однако я изо всех сил пытаюсь найти соседние слова, сопоставив буквы, и добился этого только с сопоставлением слов. Вот мой текст

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 - подземное сооружение.

Моя настоящая цель - в конечном итоге заменить все сокращения в тексте ( USNS , UGF , NFZ , AR ) с соответствующими длинными формами ( United States Navy Seals , подземный объект , бесполетная зона , штурмовая винтовка ).

Ответы [ 2 ]

2 голосов
/ 09 мая 2020

В вашем последнем регулярном выражении [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

Используя inv В таком глоссарии вы можете легко заменить все длинные формы соответствующими сокращениями. Немного сложнее сделать это для всех, кроме первого случая. Есть много места для уточнения, например, для правильной обработки разрывов строк в длинных формах (также можно использовать 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

Сама замена предоставляется читателю.


[1] Давайте еще раз подробнее рассмотрим ваше первое регулярное выражение :

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

Граничные привязки (\b) избыточны. Их можно удалить, ничего не меняя в результате, потому что \W+? означает хотя бы один символ, не являющийся словом, после последнего символа States и Navy. Здесь они не вызывают проблем, но я предполагаю, что они привели к путанице, когда вы начали, изменив его, чтобы получить более общий.

0 голосов
/ 09 мая 2020

Вы можете использовать приведенное ниже регулярное выражение, которое также позаботится о чувствительности к регистру. Щелкните здесь . .

Здесь можно найти только Печать ВМС США.

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

Точно так же для UF вы можете использовать - \s[u|U].*?[g|G].*?[f|F]\w+

Пожалуйста, найдите образец выше. Символы просто объединяются с .*?, и каждый символ используется как [a|A], что соответствует либо нижнему, либо верхнему регистру. Началом будет \s, так как это должно быть слово, а в конце - \w+.

Поиграйте.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...