Wenn ich diese Zeichenfolge habe:
2+24*48/32
wie diese Liste am effizientesten zu erstellen ist:
['2', '+', '24', '*', '48', '/', '32']
Wenn ich diese Zeichenfolge habe:
2+24*48/32
wie diese Liste am effizientesten zu erstellen ist:
['2', '+', '24', '*', '48', '/', '32']
Zufälligerweise sind die Token, die Sie aufteilen wollen, bereits Python-Token, so dass Sie die eingebaute tokenize
Modul. Es ist fast ein Einzeiler: dieses Programm:
from io import StringIO
from tokenize import generate_tokens
STRING = 1
print(
list(
token[STRING]
for token in generate_tokens(StringIO("2+24*48/32").readline)
if token[STRING]
)
)
erzeugt diese Ausgabe:
['2', '+', '24', '*', '48', '/', '32']
Anstatt manuell zuzuweisen STRING=1
können Sie die Konstante aus der token
Modul, indem es eine from token import STRING
. Dies ist besonders nützlich, wenn Sie mehrere Token-Konstanten benötigen.
Sie können verwenden split
von der re
Modul.
re.split(muster, zeichenkette, maxsplit=0, flags=0)
Zeichenkette durch die Vorkommen des Musters teilen. Wenn einfangende Klammern im Muster verwendet werden, wird der Text aller Gruppen im Muster auch als Teil der resultierenden Liste zurückgegeben.
Beispiel-Code:
import re
data = re.split(r'(\D)', '2+24*48/32')
\D
Wenn das UNICODE-Flag nicht angegeben ist, \D passt auf jede nicht-zifferige ; dies entspricht der Menge [^0-9].
Dies sieht nach einem Parsing-Problem aus, und so sehe ich mich gezwungen, eine Lösung auf der Grundlage von Parsing-Techniken zu präsentieren.
Auch wenn es den Anschein hat, dass Sie diese Zeichenfolge "aufteilen" wollen, denke ich, dass Sie sie eigentlich "tokenisieren" wollen. Tokenisierung oder Lexxing ist der Kompilierungsschritt vor dem Parsen. Ich habe mein ursprüngliches Beispiel in einem Edit geändert, um hier einen richtigen rekursiven anständigen Parser zu implementieren. Dies ist der einfachste Weg, einen Parser von Hand zu implementieren.
import re
patterns = [
('number', re.compile('\d+')),
('*', re.compile(r'\*')),
('/', re.compile(r'\/')),
('+', re.compile(r'\+')),
('-', re.compile(r'\-')),
]
whitespace = re.compile('\W+')
def tokenize(string):
while string:
# strip off whitespace
m = whitespace.match(string)
if m:
string = string[m.end():]
for tokentype, pattern in patterns:
m = pattern.match(string)
if m:
yield tokentype, m.group(0)
string = string[m.end():]
def parseNumber(tokens):
tokentype, literal = tokens.pop(0)
assert tokentype == 'number'
return int(literal)
def parseMultiplication(tokens):
product = parseNumber(tokens)
while tokens and tokens[0][0] in ('*', '/'):
tokentype, literal = tokens.pop(0)
if tokentype == '*':
product *= parseNumber(tokens)
elif tokentype == '/':
product /= parseNumber(tokens)
else:
raise ValueError("Parse Error, unexpected %s %s" % (tokentype, literal))
return product
def parseAddition(tokens):
total = parseMultiplication(tokens)
while tokens and tokens[0][0] in ('+', '-'):
tokentype, literal = tokens.pop(0)
if tokentype == '+':
total += parseMultiplication(tokens)
elif tokentype == '-':
total -= parseMultiplication(tokens)
else:
raise ValueError("Parse Error, unexpected %s %s" % (tokentype, literal))
return total
def parse(tokens):
tokenlist = list(tokens)
returnvalue = parseAddition(tokenlist)
if tokenlist:
print 'Unconsumed data', tokenlist
return returnvalue
def main():
string = '2+24*48/32'
for tokentype, literal in tokenize(string):
print tokentype, literal
print parse(tokenize(string))
if __name__ == '__main__':
main()
Die Implementierung der Behandlung von Klammern wird dem Leser als Übung überlassen. In diesem Beispiel wird die Multiplikation korrekt vor der Addition ausgeführt.
Ich lese jetzt etwas über Tokenisierung, um es zu verstehen. Ich kann also nicht sagen, wo das Problem liegt, aber ich denke, es liegt daran, dass dieses Skript * und / gleichzeitig auswertet, was nicht korrekt ist. 8/2*2 Diese Zeichenkette sollte ein Ergebnis von 2 ausgeben, aber sie gibt ein Ergebnis von 8 aus.
Entschuldigen Sie mich, ich habe bomdas immer wörtlich genommen. Es stellt sich heraus, dass Multiplikation und Division in der Reihenfolge der Vorhersage gleich sind und dass das, was zuerst auftritt, zuerst ausgewertet wird
>>> import re
>>> re.findall(r'\d+|\D+', '2+24*48/32=10')
['2', '+', '24', '*', '48', '/', '32', '=', '10']
Entspricht aufeinanderfolgenden Ziffern oder aufeinanderfolgenden Nicht-Ziffern.
Jede Übereinstimmung wird als neues Element in der Liste zurückgegeben.
Je nach Verwendung müssen Sie den regulären Ausdruck möglicherweise ändern. Zum Beispiel, wenn Sie Zahlen mit einem Dezimalpunkt abgleichen müssen.
>>> re.findall(r'[0-9\.]+|[^0-9\.]+', '2+24*48/32=10.1')
['2', '+', '24', '*', '48', '/', '32', '=', '10.1']
Dies ist ein Parsing-Problem, daher sind weder regex noch split() die "gute" Lösung. Verwenden Sie stattdessen einen Parser-Generator.
Ich würde mir Folgendes genau ansehen pyparsing . Es gab auch einige anständige Artikel über pyparsing in der Python-Magazin .
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.
0 Stimmen
Sie wollen eine Zeichenkette in eine Liste aufteilen, aber Sie wollen nicht .split() verwenden, weil es eine Liste zurückgibt? Du widersprichst dir selbst. Wenn Sie keine Liste wollen, was wollen Sie dann tun wollen?
1 Stimmen
@Jim: Ich denke, Jibmo meint, dass split() nur die Angabe eines Trennzeichens erlaubt, so dass er es einmal für '+', einmal für '-', einmal für '/' usw. aufrufen müsste.
2 Stimmen
Sorry für die schlechte Erklärung, was ich meinte, ist, dass Split eine Liste zurückgibt, was bedeutet, für die zweite Split, ich muss jetzt über Zeichenfolgen innerhalb einer Liste zu iterieren. syntaktisch falsches Beispiel. string = "2+2-2" Liste = string.split(+) gibt ['2', '+', '2-2'] jetzt muss ich über 3 Zeichenfolgen iterieren
0 Stimmen
Sie sollten erwähnen, dass Sie an einem Programm arbeiten, das in der Lage sein muss, diese Zeichenketten als arithmetische Ausdrücke auszuwerten. Jerubs Antwort deckt das ab, aber das liegt daran, dass er ein Gedankenleser ist.
0 Stimmen
Warum verwenden Sie nicht einfach SymPy ? Es sollte das tun, was Sie zu erreichen versuchen.
0 Stimmen
Es ist nicht klar, ob Sie mit Fließkommazahlen/Dezimalzahlen oder ganzen Zahlen arbeiten. Ich meine, sollte das '.' (oder ',' für einige Länder) auch geteilt werden?