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

#regex #python-3.x

#регулярное выражение #python-3.x

Вопрос:

Я создал следующее регулярное выражение в Python 3, чтобы найти все слова в нижнем регистре в тексте и сослаться на первую букву и конец этого слова. Пример:

 w          ord
^          ^^^
|          |
1st letter tail
  

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

 str = "Some text here and some more after that. Something that should remain untouched."
for match in re.finditer(r"b([a-z])([a-z] )b", str):
    # print(match.group(1).upper()   match.group(2)) # just for debugging
    str = re.sub(r"b"   match.group(1).upper()   match.group(2)   r"b", match.group(1)   match.group(2), str)

print(str) #print the desired result
  

Есть ли способ сделать это в Python 3 с помощью одного регулярного выражения и без дополнительного процедурного кода? Кажется, что должен быть более элегантный способ, но я его не вижу (пока).

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

Пожалуйста, обратите внимание, что RegEx-Replace может соответствовать только целым словам, но не частичным словам. 5-е слово в моем тексте — «some», это приводит к преобразованию 1-й буквы 1-го слова («Some») в в нижний регистр, но оставляет слово «Что-то», с которого начинается 2-е предложение, нетронутым.

Комментарии:

1. Можете ли вы просто описать, что вы пытаетесь получить вместо как вы пытаетесь это сделать? Простого до и после должно быть достаточно.

2. Ну, я хочу преобразовать все слова, начинающиеся с заглавной буквы, в одно и то же слово в нижнем регистре, ЕСЛИ слово встречается хотя бы один раз в нижнем регистре в тексте. Опубликованный мной код делает это правильно, но я пытаюсь избавиться от for и просто выполнить задачу только с регулярным выражением.

Ответ №1:

Вы не можете этого сделать с помощью re module , поскольку он не поддерживает поиск переменной длины сзади, и поскольку при использовании встроенного модификатора, подобного (?i) , он устанавливается для всего шаблона, и вы не можете его отключить. Это можно сделать с новым regex module с помощью этого шаблона:

 b([A-Z][a-z]*)b(?:(?=.*b(?=[a-z] b)(?i)1b)|(?<=b(?=[a-z] b)(?i)1b. ))
  

Однако я не уверен, что это более «элегантный» способ.

Можно протестировать шаблон с<a rel="noreferrer noopener nofollow" href="https:///regexstorm.net/tester?p=b([A-Z][a-z]*)b(?:(?=.*b(?=[a-z]+b)(?i)1b)|(?regexstorm.net/tester (поскольку движок регулярных выражений .net также допускает поисковые запросы переменной длины.)

Обратите внимание, что область действия встроенного модификатора ограничена подшаблоном после него и заканчивается первой закрывающей скобкой.

Комментарии:

1. Потрясающе, это именно то, что я искал. Оно стало немного больше, чем я ожидал, после того, как я потратил время на его просмотр, я думаю, что это довольно просто. Также БОЛЬШОЕ спасибо за ссылку regexstorm. Я раньше не знал эту страницу, здорово провести несколько быстрых тестов с регулярными выражениями и быстро получить визуальную обратную связь.