Как исключить группу символов в питоне - PullRequest
1 голос
/ 22 сентября 2019

Я хочу написать скрипт, который возвращает цифры со степенью 1. Входные данные пользователя являются квадратичными и обычными цифрами.то, что я хочу, описано ниже:

input = "+2**5+3+4**8-7"
Output = "3,-7"

Я пробовал регулярное выражение re.findall(r"[+-]?[0-9]+[^[*][*][2]]", input), но оно не работает Спасибо заранее:)

Ответы [ 4 ]

3 голосов
/ 22 сентября 2019

Вам необходимо отрицательное утверждение о просмотре и добавить привязки границ:

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]
2 голосов
/ 22 сентября 2019

Вы можете написать парсер и проверить все, что вам нужно.Я знаю, что это немного долго, но весело :)

$ cat lexer.py
import re
from collections import namedtuple

tokens = [
    r'(?P<TIMES>\*)',
    r'(?P<POW>(\+|-)?\d+\*\*\d+)',
    r'(?P<NUM>(\+|-)?\d+)'
    ]

master_re = re.compile('|'.join(tokens))
Token = namedtuple('Token', ['type','value'])
def tokenize(text):
    scan = master_re.scanner(text)
    return (Token(m.lastgroup, m.group())
            for m in iter(scan.match, None))

x = '+2**5+3+4**8-7'

required = []
for tok in tokenize(x):
  if tok.type == 'POW':
      coeff, exp = tok.value.split('**')
      if exp == '1':
          required.append(coeff)
  elif tok.type == 'NUM':
      required.append(tok.value)

print(required)

Вывод:

$ python lexer.py
['+3', '-7']
2 голосов
/ 22 сентября 2019
re.findall(r"(?<!\*\*)(?<!\*\*[+-])[+-]?\b[0-9]++(?!\*\*)", input)

(?!\*\*) - это отрицательный прогноз, который гарантирует, что мы не имеем 2 * после цифр.

re не поддерживает возможные квантификаторы, вы должны использовать PyPi регулярное выражение

Демо

0 голосов
/ 22 сентября 2019

Вы можете попробовать это простое регулярное выражение

re.findall(r'[-\+]\d(?!\*\*)', search_data)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...