Python: конвертировать кортежи из re.findall в строку?

Я хочу прочитать текст, использовать регулярные выражения, чтобы найти все экземпляры шаблона, а затем распечатать соответствующие строки. Если я использую метод re.search(), я могу успешно получить и распечатать первый экземпляр нужного шаблона:

import re

text = "Cello is a yellow parakeet who sings with Lillian. Toby is a clown who doesn't sing. Willy is a Wonka. Cello is a yellow Lillian."

match = re.search(r'(cello|Cello)(\W{1,80}\w{1,60}){0,9}\W{0,20}(lillian|Lillian)', text)
print match.group()

К сожалению, метод re.search() находит только первый экземпляр нужного шаблона, поэтому я заменил re.findall():

import re

text = "Cello is a yellow parakeet who sings with Lillian. Toby is a clown who doesn't sing. Willy is a Wonka. Cello is a yellow Lillian."

match = re.findall(r'(cello|Cello)(\W{1,80}\w{1,60}){0,9}\W{0,20}(lillian|Lillian)', text)
print match

Эта процедура находит оба экземпляра целевого шаблона в примере текста, но я не могу найти способ напечатать предложения, в которых встречаются шаблоны. Функция печати этого последнего бита кода выдает: ('Cello', ' with', 'Lillian'), ('Cello', ' yellow', 'Lillian') вместо вывода, который я желаю: "Cello is a желтый попугай, который поет с Лилиан. Виолончель - это желтая Лилиан."

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

2 ответа

Решение

Я бы просто сделал большую группу захвата вокруг двух конечных точек:

import re

text = "Cello is a yellow parakeet who sings with Lillian. Toby is a clown who doesn't sing. Willy is a Wonka. Cello is a yellow Lillian."

for match in re.findall(r'(Cello(?:\W{1,80}\w{1,60}){0,9}\W{0,20}Lillian)', text, flags=re.I):
    print match

Теперь вы получите два предложения:

Cello is a yellow parakeet who sings with Lillian
Cello is a yellow Lillian

Несколько советов:

  • flags=re.I делает регулярное выражение без учета регистра, поэтому Cello соответствует обоим cello а также Cello,
  • (?:foo) так же, как (foo)за исключением того, что захваченный текст не будет отображаться как совпадение. Это полезно для группировки вещей без согласования.

Описание

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

(?:(?<=\.)\s+|^)((?=(?:(?!\.(?:\s|$)).)*?\b[Cc]ello(?=\s|\.|$))(?=(?:(?!\.(?:\s|$)).)*?\b[Ll]illian(?=\s|\.|$)).*?\.(?=\s|$))

введите описание изображения здесь

Выражение разбито на следующие функциональные компоненты:

  • (?:(?<=\.)\s+|^) начать сопоставлять это предложение в после . с последующим любым количеством пробелов или в начале строки
  • ( начать захват группы 1, которая захватит все это предложение
  • (?= начать смотреть в будущее
    • (?:(?!\.(?:\s|$)).)*? убедитесь, что механизм регулярных выражений не оставляет это предложение, заставляя его признать . с последующим пробелом или концом строки
    • \b сопоставить слово перерыв
    • [Cc]ello соответствовать желаемому тексту либо в нижнем регистре, либо с заглавной буквы
    • (?=\s|\.|$) посмотрите вперед, чтобы убедиться, что строка имеет завершающий пробел, .или конец строки
    • ) конец будущего
  • (?=(?:(?!\.(?:\s|$)).)*?\b[Ll]illian(?=\s|\.|$)) это по сути то же самое, но для Лилиан
  • .*?\.(?=\s|$) захватить оставшуюся часть предложения до и включая точку, и убедиться, что за точкой следует либо пробел, либо конец строки
  • ) конец группы захвата предложения 1

Пример кода

Я не знаю Python достаточно хорошо, поэтому я предлагаю пример PHP. Обратите внимание, в заявлении о совпадении я использую s опция, которая позволяет . выражение для соответствия символам новой строки

Введите текст

Cello is a yellow parakeet who sings with Lillian. Toby is a clown who doesn't sing. Willy is a Wonka. Cello is a yellow Lillian.
Cello likes Lillian and kittens.
Lillian likes Cello and dogs.  Cello has no friends. And Lillian also hasn't met anyone.

Код

<?php
$sourcestring="your source string";
preg_match_all('/(?:(?<=\.)\s+|^)((?=(?:(?!\.(?:\s|$)).)*?\b[Cc]ello(?=\s|\.|$))(?=(?:(?!\.(?:\s|$)).)*?\b[Ll]illian(?=\s|\.|$)).*?\.(?=\s|$))/s',$sourcestring,$matches);
echo "<pre>".print_r($matches,true);
?>

Матчи

$matches Array:
(
    [0] => Array
        (
            [0] => Cello is a yellow parakeet who sings with Lillian.
            [1] =>  Cello is a yellow Lillian.
            [2] => 
Cello likes Lillian and kittens.
            [3] => 
Lillian likes Cello and dogs.
        )

    [1] => Array
        (
            [0] => Cello is a yellow parakeet who sings with Lillian.
            [1] => Cello is a yellow Lillian.
            [2] => Cello likes Lillian and kittens.
            [3] => Lillian likes Cello and dogs.
        )

)

Если вам абсолютно необходимо сопоставить предложения, в которых строка "Виолончель" появляется перед "Лилиан", то вы используете такое выражение. Здесь я просто переместил единственные закрывающие скобки.

(?:(?<=\.)\s+|^)((?=(?:(?!\.(?:\s|$)).)*?\b[Cc]ello(?=\s|\.|$)(?=(?:(?!\.(?:\s|$)).)*?\b[Ll]illian(?=\s|\.|$))).*?\.(?=\s|$))

введите описание изображения здесь

Введите текст

Cello is a yellow parakeet who sings with Lillian. Toby is a clown who doesn't sing. Willy is a Wonka. Cello is a yellow Lillian.
Cello likes Lillian and kittens.
Lillian likes Cello and dogs.  Cello has no friends. And Lillian also hasn't met anyone.

Выход для группы захвата 1

[1] => Array
    (
        [0] => Cello is a yellow parakeet who sings with Lillian.
        [1] => Cello is a yellow Lillian.
        [2] => Cello likes Lillian and kittens.
    )
Другие вопросы по тегам