Найти числа в строке, изменить и заново объединить

1

Probem:

У меня есть строка, содержащая разные числа, математические знаки и слова, например

str = ".1**2 + x/(10.0 - 2.E-4)*n_elts"

Я хотел бы извлечь все числа и сохранить части между номерами, чтобы потом поместить их вместе позже (после работы с числами).

lst = [".1", "**", "2", " + ", "x/(", "10.0", " - ", "2.E-4", ")*n_elts"]

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

"".join(process(l) for l in lst)

где процесс может выглядеть так (предложения для лучшего способа проверить l - это число приветствуется):

def process(l):
    try:
        n = float(l)
    except ValueError:
        return l
    else:
        return work_on_it(l)

Текущее состояние:

Из этого ответа я выяснил, как сохранить делиминаторы и проработал мой путь к

lst = re.split('( |\+|\-|\*|/)', ".1**2 + x/(10.0 - 2.E-4)*n_elts")

Теперь мне нужно как-то избежать расщепления 2.E-4.

Я попытался выработать регулярное выражение (синтаксис vi, надеюсь, что это универсальный), который охватывает все числа, которые могут появиться и думать

\d*\.\d*[E|e]*[|+|-]*\d*

должно быть хорошо.

Одна из стратегий заключалась бы в том, чтобы каким-то образом получить это re.

Я также нашел связанный ответ, который, похоже, выполняет часть, соответствующую числу. Это может быть немного сложнее, чем мне нужно, но в основном я не знаю, как его сочетать с битом хранения ограничителей.

Теги:

2 ответа

2
Лучший ответ

Одно общее замечание: внутри классов персонажей вы не используете | , потому что он просто рассматривается как другой символ, который нужно сопоставить. Внутри классов символов допустимые символы просто перечисляются друг за другом.

Чтобы действительно решить вашу проблему: поскольку вы все равно сохраняете разделители, неважно, правильно ли вы соответствуете номерам или не номерам? Просто используйте

lst = re.split(r'(\d*\.\d*[Ee]*[+-]*\d*)', ".1**2 + x/(10.0 - 2.E-4)*n_elts")

Возможно, вам захочется немного улучшить регулярное выражение числа:

lst = re.split(r'((?:\d+\.\d*|\.?\d+)(?:[Ee][+-]?\d+)?)', ".1**2 + x/(10.0 - 2.E-4)*n_elts")

Таким образом, вы делаете десятичную точку необязательной, но требуете хотя бы одну цифру до или после нее. Это также делает экспоненциальную часть полностью необязательной, но обеспечивает ее корректную форматирование, если она присутствует. " ?: Подавляет захват. В противном случае эти внутренние группы будут делать то же самое, что и внешний набор круглых скобок, и добавить части, которые сопоставляются внутри с результатом split - вы не хотите этого, потому что это даст вам полное число, часть до экспоненциальной и экспоненциальной. Поэтому вам нужно использовать ?: Для подавления захвата (что обычно является хорошей привычкой, если вам явно не требуется захват).

Наконец, обратите внимание на использование необработанных строк (r перед строковым литералом). Без этого экранирование может стать действительно уродливым (в этом вам, возможно, придется дважды сбежать из метасимволов регулярных выражений). В Python вы всегда должны использовать необработанные строки для обозначения шаблонов регулярных выражений.

2

Вы можете использовать этот re.split() с возвращаемым регулярным выражением regex с нечетными индексами, например:

import re

s = ".1**2 + x/(10.0 - 2.E-4)*n_elts"
parts = re.split(r"([+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?)", s)
parts[1::2] = [str(100 * float(f)) for f in parts[1::2]]
print("".join(parts))
# -> 10.0**200.0 + x/(1000.0 - 0.02)*n_elts

где регулярное выражение задается из вопроса Python и regex, извлекайте float/double value.

  • 0
    ... при условии, что он начинается с числа, а не унарный оператор ...
  • 0
    @ChrisF: никаких предположений. Из документов: компоненты-разделители всегда находятся с одинаковыми относительными индексами в списке результатов . Попробуй это .
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню