Я начинающий программист, и SonarLint говорит мне, что код слишком сложный. Я пробовал рекурсию, итераторы, нарезку, но мне не удалось упростить этот код. Кто-нибудь может мне помочь?
txt = "A **A** is *italic* **bold** but some are *a* *b* **B**"
def fun(text=None):
if text:
bold_splits = text.split('**')
for i, s in enumerate(bold_splits):
if i % 2:
print('BOLD:', s )
else:
italic_splits = s.split('*')
for m, n in enumerate(italic_splits):
if m % 2:
print('ITALIC:', n )
else:
if n != '':
print('NORMAL:', n )
1 ответ
Похоже, вы пытаетесь извлечь информацию из строки. Чаще всего это делается с помощью регулярных выражений, поскольку они часто быстрее, чем ваш собственный код, но при этом менее сложны.
Поскольку пока у вас нет четкого описания вашей цели, я делаю следующие предположения из вашего кода:
- Вы хотите разделить каждую последовательность символов в своей строке на одну из категорий, выделенных жирным шрифтом, курсивом и обычным шрифтом, в зависимости от символов, заключенных в 2, 1 или 0 звездочек.
- Вы хотите сохранить порядок исходной строки.
Если мы запретим звездочки в обычном тексте, регулярное выражение для этого будет довольно простым. Я рекомендую изучить, что он делает на regex101.
**(?P<bold>.+?)**|*(?P<italic>.+?)*|(?P<normal>[^*]+)
Примечательно, что | совпадения символов в первом найденном совпадении слева направо, что означает, что совпадение всегда будет пытаться найти жирный шрифт, затем курсив, а затем обычный.
В Python мы можем перебирать все совпадения, используя re.finditer. Для каждого match, lastgroup вернет имя захваченной группы, поэтому мы можем использовать его в нашем операторе печати, а также использовать его для получения фактического совпадения, которое нас интересует.
def fun(text=None):
if text:
for match in re.finditer(r'**(?P<bold>.+?)**|' # match bold lazily
r'*(?P<italic>.+?)*|' # match italics lazily
r'(?P<normal>[^*]+)', # match normal greedily
text):
print(f'{match.lastgroup.upper()}: {match.group(match.lastgroup)}')
Следует отметить, что если функция вызывается много раз и производительность вызывает беспокойство, вам следует один раз скомпилировать регулярное выражение, прежде чем использовать его в fun.
Регулярное выражение, используемое в этом примере, очень примитивно, потому что вы не указали свои ограничения или даже то, что функция должна делать. Уточнив свой вопрос и объяснив, как крайние случаи нравятся ** a ** *** и **ab*cd** должен себя вести, можно дать более полный ответ.
![Высокая сложность кода SonarLint [closed] TheFAQ.ru](https://thefaq.ru/wp-content/uploads/2023/01/logo-250.png)
FWIW для поддержки
**ab*cd**вы можете изменить жирный шрифт[^*]+к.+?. Мы можем сделать то же самое для курсива, но пока ничего не изменится. Нежадные поисковые запросы IMO обычно более полезны.— Пейлонрайз
@Peilonrayz Я отредактировал сообщение, чтобы включить ваше предложение, так как оно действительно чище, спасибо.
— Итерниам
От документация «RE, разделенные символом» | » пробуются слева направо. Когда один шаблон полностью совпадает, эта ветвь принимается. Это означает, что после совпадения A B не будет тестироваться дальше, даже если это приведет к более длительному общему совпадению. Другими словами, ‘|’ оператор никогда не бывает жадным. «
— RootTwo
@RootTwo Я поправил в посте. Изначально я тестировал соответствие
aba|aabaaпротивaabaa, который соответствует последнему, что привело меня к выводу, что использовалось самое длинное совпадение. Вместо этого, похоже, потому чтоaabaaвстречается раньше в строке.— Итерниам