У меня есть строки этой формы:
A_B_CDEF_GHI
A_B_C_DEF_G_H_I
ABC_D_E_F_GHI
ABCDEFG_H_I
A_B_C
Мне нужно преобразовать их в следующее:
AB_CDEF_GHI
ABC_DEF_GHI
ABC_DEF_GHI
ABCDEFG_HI
ABC
Итак, правила:
(._){2,}
следует преобразовать в XXX_
, если он не находится в конце строки.(_.){2,}
встречается в конце строки, его следует преобразовать в _XXX
.(_.){2,}.
является строкой весь, все символы подчеркивания должны быть удалены.Я добрался до (((.)_){2,})
, что соответствует первому правилу, но как я могу заменить его найденными символами без подчеркивания?
The
python
tag is present because that's where the code is, and I know regex dialects depend on the language.
'____B_CDEF_GHI'
(4 знака подчеркивания в начале) превратиться в 'B_CDEF_GHI'
?
Точка в вашем примере кода соответствует любому символу, включая подчеркивание. Вместо этого вы можете сделать шаблон немного более конкретным.
Вы можете убрать все двойные совпадения A-Z и захватить одиночные A-Z, за которыми следуют _
и A-Z в группе.
Затем для группы захвата замените _
пустой строкой.
_?[A-Z]{2,}_?|([A-Z](?:_[A-Z](?![A-Z]))+)
_?[A-Z]{2,}_?
Сопоставьте 2 или более вхождений A-Z, окруженных необязательными символами подчеркивания.|
или(
Захватить группа 1[A-Z]
Сопоставьте один A-Z(?:_[A-Z](?![A-Z]))+
Повторите 1+ раз _
и AZ, утверждая, а не AZ вправо)
Закрыть группу 1См. демонстрация регулярных выражений и демонстрация Python
Например:
import re
pattern = r'_?[A-Z]{2,}_?|([A-Z](?:_[A-Z](?![A-Z]))+)'
s = ("A_B_CDEF_GHI\n"
"A_B_C_DEF_G_H_I\n"
"ABC_D_E_F_GHI\n"
"ABCDEFG_H_I\n"
"A_B_C")
res = re.sub(pattern, lambda x: x.group(1).replace("_", "") if x.group(1) else x.group(), s)
print(res)
Выход
AB_CDEF_GHI
ABC_DEF_GHI
ABC_DEF_GHI
ABCDEFG_HI
ABC
Немного более широкое соответствие вместо символов A-Z может заключаться в использовании класса отрицательных символов, соответствующего любому символу, кроме символа пробела или символа подчеркивания.
_?[^_\s]{2,}_?|([^_\s](?:_[^_\s](?![^_\s]))+)
Большое спасибо. Это сработало отлично. Сэкономил столько времени, пытаясь понять, как это сделать программно.
Вот решение без регулярных выражений:
def convert(s: str) -> str:
""" https://stackoverflow.com/q/71578300 """
def _get_combined_parts() -> Iterator[str]:
"""
yields the ``_``-separated parts of ``s``
where subsequent single-character parts have been combined
"""
combined_part = ""
for part in s.split("_"):
if len(part) <= 1:
combined_part += part
else:
if combined_part:
yield combined_part
yield part
combined_part = ""
if combined_part:
yield combined_part
return "_".join(_get_combined_parts())
Несколько измерений в моей системе показывают, что мое решение в два раза быстрее, чем решение stackoverflow.com/a/71578365/13134095. ?
Как приятно читать четкий, лаконичный, недвусмысленный вопрос!