Я пытаюсь захватить слова в строке так, чтобы первое слово начиналось с s, а регулярное выражение переставало совпадать, если следующее слово также начиналось с s.
Например. У меня есть строка «Стек, код и StackOverflow». Я хочу захватить только «Стек, код и» и не включать «StackOverflow» в соответствие.
Вот что я думаю:
Регулярное выражение, которое я пробовал:
(?<=\s)S[a-z -,]*(?!(\sS))
Я не знаю, как заставить его работать.
Я думаю, это должно сработать. Я адаптировал регулярное выражение из этой темы . Вы также можете протестировать здесь. Я также включил решение без регулярных выражений. Я в основном отслеживаю первое вхождение слова, начинающегося с «s», и следующего слова, начинающегося с «s», и получаю слова в этом диапазоне.
import re
teststring = " Stack, Code and StackOverflow"
extractText = re.search(r"(\s)[sS][^*\s]*[^sS]*", teststring)
print(extractText[0])
#non-regex solution
listwords = teststring.split(' ')
# non regex solution
start = 0
end = 0
for i,word in enumerate(listwords):
if word.startswith('s') or word.startswith('S'):
if start == 0:
start = i
else:
end = i
break
newstring = " " + " ".join([word for word in listwords[start:end]])
print(newstring)
Stack, Code and
Stack, Code and
Вы можете использовать, например, группу захвата:
(S(?<!\S.).*?)\s*S(?<!\S.)
Объяснение
(
Группа захвата 1
S(?<!\S.)
Соответствуйте S
и утверждайте, что слева от S
нет границы пробела.*?
Сопоставьте любого персонажа, как можно меньше)
Закрыть группу\s*
Соответствие необязательным пробельным символамS(?<!\S.)
Соответствуйте S
и утверждайте, что слева от S
нет границы пробелаПосмотрите демонстрацию регулярных выражений и демонстрацию Python.
Пример кода:
import re
pattern = r"(S(?<!\S.).*?)\s*S(?<!\S.)"
s = "Stack, Code and StackOverflow"
m = re.search(pattern, s)
if m:
print(m.group(1))
Выход
Stack, Code and
Другой вариант, использующий обходной путь, чтобы утвердить S
справа и не использовать его, чтобы разрешить несколько совпадений друг за другом:
S(?<!\S.).*?(?=\s*S(?<!\S.))
Демонстрация регулярных выражений
import re
pattern = r"S(?<!\S.).*?(?=\s*S(?<!\S.))"
s = "Stack, Code and StackOverflow test Stack"
print(re.findall(pattern, s))
Выход
['Stack, Code and', 'StackOverflow test']
@Izhar Вы хотите несколько совпадений в одной строке?
На самом деле я хочу зафиксировать только последнее совпадение в строке. Итак, в приведенном выше примере мне нужен только «тест StackOverflow». Я работаю над извлечением пары акроним-расширение в предложении. Например, если у меня есть предложение: «Можно провести методом капиллярного электрофореза-масс-спектрометрии (КЭ-МС)». Вот мой подход: 1) Начните регулярное выражение с аббревиатуры: (CE-MS) 2) Используя regex lookbehind, сопоставьте все, но остановитесь на первом слове, которое начинается с начального символа в аббревиатуре (в данном случае C). Так что в идеале я бы остановился на слове «капилляр».
Однако у меня были проблемы с реализацией этого, но ваше решение определенно помогло. У меня все еще есть несколько редких ложных срабатываний, когда совпадение содержит больше слов, чем означает аббревиатура, но я готов принять это. Я ценю любые предложения о том, как улучшить мой подход или придумать что-то совершенно новое.
@Izhar Можете ли вы привести пример, когда это не удается?
Я использовал ваш ответ и ответ выше и придумал следующее регулярное выражение. (?<!{p0})(?<= ){p0}[a-z -]*{p1}?[az ]*\s?(?<=){pl}[az ]*\s(?<= )({шаблон}) где {p0} — первый символ в шаблоне, {p1} — второй, а {pl} — последний. В настоящее время он имеет вероятность успеха 92%, но не работает на некоторых входных данных (примеры строк, показанные в окне регулярного выражения) Демонстрация регулярного выражения
Спасибо за помощь. И ваш ответ, и ответ выше решают именно мою проблему.