Регулярное выражение Python: сопоставьте ВСЕ последовательные заглавные слова

Короткий вопрос:

У меня есть строка:

title="Announcing Elasticsearch.js For Node.js And The Browser"

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

Итак, ожидаемый результат должен быть:

['Announcing Elasticsearch.js', 'Elasticsearch.js For', 'For Node.js', 'Node.js And', 'And The', 'The Browser']

То, что у меня есть прямо сейчас, это:

'[A-Z][a-z]+[\s-][A-Z][a-z.]*'

Это дает мне вывод:

['Announcing Elasticsearch.js', 'For Node.js', 'And The']

Как я могу изменить свое регулярное выражение, чтобы получить желаемый результат?


person KGo    schedule 17.12.2013    source источник
comment
Возможно, связано: stackoverflow.com/q/15799332/1578604   -  person Jerry    schedule 18.12.2013
comment
Похоже, вы хотите переместить последнюю совпавшую позицию на слово назад. Можно ли получить пары в два приема, а не все сразу?   -  person mtanti    schedule 18.12.2013
comment
@mtanti Я думаю, это должно быть нормально, я буду анализировать только строки из 5-7 слов.   -  person KGo    schedule 18.12.2013


Ответы (3)


Вы можете использовать это:

#!/usr/bin/python
import re

title="Announcing Elasticsearch.js For Node.js And The Browser TEst"
pattern = r'(?=((?<![A-Za-z.])[A-Z][a-z.]*[\s-][A-Z][a-z.]*))'

print re.findall(pattern, title)

«Нормальный» шаблон не может соответствовать перекрывающимся подстрокам, все символы создаются один раз и навсегда. Однако просмотр вперед (?=..) (т. е. «за которым следует») — это только проверка и ничего не соответствует. Он может анализировать строку несколько раз. Таким образом, если вы поместите захватываемую группу внутрь просмотра вперед, вы можете получить перекрывающиеся подстроки.

person Casimir et Hippolyte    schedule 17.12.2013
comment
Можете ли вы объяснить немного больше о том, как это работает? Может быть, развернутая версия? - person KGo; 18.12.2013
comment
Что делать, если я хочу ограничить длину захваченной группы? - person TomSawyer; 03.01.2020

Вероятно, есть более эффективный способ сделать это, но вы можете использовать регулярное выражение, подобное этому:

(\b[A-Z][a-z.-]+\b)

Затем выполните итерацию по группам захвата, таким образом, проверяя это регулярное выражение: (^[A-Z][a-z.-]+$), чтобы убедиться, что совпадающая группа (текущая) соответствует совпадающей группе (следующей).

Рабочий пример:

import re

title = "Announcing Elasticsearch.js For Node.js And The Browser"
matchlist = []
m = re.findall(r"(\b[A-Z][a-z.-]+\b)", title)
i = 1
if m:
    for i in range(len(m)):
        if re.match(r"(^[A-Z][a-z.-]+$)", m[i - 1]) and re.match(r"(^[A-Z][a-z.-]+$)", m[i]):
            matchlist.append([m[i - 1], m[i]])

print matchlist

Вывод:

[
    ['Browser', 'Announcing'], 
    ['Announcing', 'Elasticsearch.js'], 
    ['Elasticsearch.js', 'For'], 
    ['For', 'Node.js'], 
    ['Node.js', 'And'], 
    ['And', 'The'], 
    ['The', 'Browser']
]
person brandonscript    schedule 17.12.2013

Если ваш код Python на данный момент таков

title="Announcing Elasticsearch.js For Node.js And The Browser"
results = re.findall("[A-Z][a-z]+[\s-][A-Z][a-z.]*", title)

то ваша программа пропускает пары с нечетными номерами. Простым решением было бы исследовать шаблон, пропустив первое слово следующим образом:

m = re.match("[A-Z][a-z]+[\s-]", title)
title_without_first_word = title[m.end():]
results2 = re.findall("[A-Z][a-z]+[\s-][A-Z][a-z.]*", title_without_first_word)

Теперь просто объедините результаты и результат2 вместе.

person mtanti    schedule 17.12.2013