Вам необходимо отрицательное утверждение о просмотре и добавить привязки границ:
r'(?<!\*\*)-?\b\d+\b(?!\*\*)'
Синтаксис (?<!...)
соответствует только в тех местах, где текст до него не совпадаетшаблон.Точно так же синтаксис (?!...)
делает то же самое для после текста.Вместе они обеспечивают совпадение только с числами, которые не являются показателями степени (следуйте **
) и не имеют показателя степени (за которым следует **
).
Граничный якорь \b
соответствует только в начале или в концестрока, где бы ни находился символ слова, за которым следует символ, не являющийся словом, или наоборот (например, между \w\W
или \W\w
, где \w
включает в себя цифры, но не арифметические символы):
>>> import re
>>> input = "+2**5+3+4**8-7"
>>> re.findall(r'(?<!\*\*)-?\b\d+\b(?!\*\*)', input)
['3', '-7']
Обратите внимание, что я использовал \d
для сопоставления цифр и удалил +
из шаблона, так как вы не хотите этого в ожидаемом выводе.
Вы можете играть с выражением в online regex101 demo ;Например, вы можете попробовать это с числами> 10 и использовать один *
для умножения.
Если вы должны поддерживать отрицательные показатели, то вышеприведенного будет недостаточно, поскольку ...**-42
соответствует 42
без **
перед цифрами.В этом случае необходим дополнительный негативный взгляд перед -?
, который запрещает **-
:
r'(?<!\*\*)-?(?<!\*\*-)\b\d+\b(?!\*\*)'
(Спасибо Казимиру, например, Ипполиту за то, что указывает это и предлагаетрешение для этого).
Однако на этом этапе я бы предложил вам переключиться на простой синтаксический анализ выражения в абстрактное синтаксическое дерево и затем пройтись по дереву, чтобы извлечь операнды, которые являютсяне является частью показателя степени:
import ast
class NumberExtractor(ast.NodeVisitor):
def __init__(self):
self.reset()
def reset(self):
self.numbers = []
def _handle_number(self, node):
if isinstance(node, ast.Constant):
if isinstance(node.value, (int, float, complex)):
return node.value
elif isinstance(node, ast.Num):
return node.n
def visit_UnaryOp(self, node):
if isinstance(node.op, (ast.UAdd, ast.USub)):
operand = self._handle_number(node.operand)
if operand is None:
return
elif isinstance(node.op, UAdd):
self.numbers.append(+operand)
else:
self.numbers.add(-operand)
def visit_Constant(self, node):
if isinstance(node.value, (int, float, complex)):
self.numbers.append(node.value)
def visit_Num(self, node):
self.numbers.append(node.n)
def visit_BinOp(self, node):
if isinstance(node.op, ast.Pow):
return # ignore exponentiation
self.generic_visit(node) # process the rest
def extract(expression):
try:
tree = ast.parse(expression, mode='eval')
except SyntaxError:
return []
extractor = NumberExtractor()
extractor.visit(tree)
return extractor.numbers
Это извлекает только числа;вычитание не приведет к отрицательному числу:
>>> input = "+2**5+3+4**8-7"
>>> extract(input)
[3, 7]
Более того, оно может обрабатывать произвольное количество пробелов и гораздо более сложные выражения, чем когда-либо могло бы обработать регулярное выражение:
>>> extract("(10 + 15) * 41 ** (11 + 19 * 17) - 42")
[10, 15, 42]