Сопоставить текст между двумя словами (слова не повторяются в сопоставленном тексте)
У меня есть следующее как мой вход,
вход
Random Line 1
Random Line 2
From: person1@example.com
Date: 01-01-2011
To: friend@example.com
Subject: One
Random Line 3
Random Line 4
From: person2@example.com
Subject: Two
Random Line 5
From: person3@example.com
Subject: Three
This is the end
Ниже приведен мой ожидаемый сопоставленный текст,
Ожидаемый результат
From: person2@example.com
Subject: Two
Примечание. Между From: person2@example.com и Subject: Two может быть ноль или несколько строк.
Я пытался с регулярным выражением,
/(From.*?Subject:\s*Two)/m
Вышеуказанное регулярное выражение совпадает с первым From. Может ли кто-нибудь помочь мне в сопоставлении ожидаемого результата? Заранее спасибо.
4 ответа
Добавлять .*
перед вашим регулярным выражением, чтобы получить только ожидаемые две строки.
.*(From.*?Subject:\s*Two)
Из-за жадного квантификатора *
двигатель regex соответствует последнему From
строка (то есть та, что перед строкой, которая содержит строку Two
). Тогда из строки From
до струны Two
записывается в группу (используется не жадный квантификатор. поэтому он делает кратчайшее совпадение).
Это еще один способ:
Код
text.scan(/.*(From:.*?\n).*(Subject: Two)/m).join
пример
text = <<_
Line 1
From: person1@example.com
To: friend@example.com
Subject: One
Line 5
From: person2@example.com
Line 7
Subject: Two
Line 9
From: person3@example.com
Subject: Three
The End
_
text.scan(/.*(From:.*?\n).*(Subject: Two)/m).join
#=> "From: person2@example.com\nSubject: Two"
объяснение
Регулярное выражение
r = /.*(From:.*?\n).*(Subject: Two)/m
пропускает все символы, пока не достигнет последней строки "From:...\n"
за которым следует (после нескольких несовпадающих символов) строка "Subject Two"
, В частности:
.*
будучи жадным, потребляет столько символов, сколько может, включая строки"From:...\n"
которые не соответствуют регулярному выражению, вплоть до начала первой группы захвата.(From:.*?\n)
первая группа захвата, захват"From:
до конца этой линии.?
в.*?
марки.*
не жадный, так что останавливается на первом\n
это достигает..*
потребляет все последующие символы, пока не достигнет второй группы захвата.(Subject: Two)
это вторая группа захвата.
Убедитесь, что между первой и второй строкой есть только одна новая строка:
/(From[^\n]*\n\s*Subject:\s*Two)/m
Кроме того, я считаю, что удаление /m
сделает это еще проще:
/(From.*?\s*Subject:\s*Two)/
Если у вас могут быть строки посередине, вам нужно использовать отрицательный прогноз:
/(From[^\n]*\n(^(?!From)[^\n]*\s*)*Subject:\s*Two)/m
Это регулярное выражение делает следующее:
From[^\n]*\n
- соответствует тексту, начинающемуся сFrom
до конца линии(^(?!From)[^\n]*\s*)*
- соответствует нулю или нескольким строкам, не начинающимся с From ( отрицательный взгляд)Subject:\s*Two
- соответствует тексту, содержащемуSubject:
[Пробел]Two
Использовать этот:
if subject =~ /^From[^\r\n]*\s*\S*Subject: Two/
match = $&
else
match = ""
end
объяснение
^
якорь утверждает, что мы находимся в начале строкиFrom
соответствует буквам[^\r\n]*
соответствует любым символам, которые не являются переносами строк\s*
соответствует любому пробелу, включая разрывы строк\S*
соответствует любым символам без пробеловSubject: Two
соответствует буквам
Многострочная версия
В ответ на ваш комментарий и новую заметку, вот еще одна версия, которая позволит несколько строк между From
и Two
:
if subject =~ /^From(?:(?:(?!^From).)*+\s*+)*\S*Subject: Two/
match = $&
else
match = ""
end