2015-06-23 2 views
19

Wie der documentation angegeben ist, ist die Verwendung von regex.search(string, pos, endpos) nicht vollständig äquivalent zum Schneiden der Zeichenfolge, d. H. regex.search(string[pos:endpos]). Es wird keine Regex-Übereinstimmung als der String ist beginnend mit pos, so ^ nicht entspricht der Anfang der Teilzeichenfolge, sondern entspricht nur den tatsächlichen Anfang der gesamten Zeichenfolge. $ entspricht jedoch entweder dem Ende der Teilzeichenfolge oder der gesamten Zeichenfolge.Warum sucht die Regex-Suche in Teilzeichenfolge "nicht vollständig äquivalent zum Aufteilen der Zeichenfolge" in Python?

>>> re.compile('^am').findall('I am falling in code', 2, 12) 
    []  # am is not at the beginning 
    >>> re.compile('^am').findall('I am falling in code'[2:12]) 
    ['am'] # am is the beginning 
    >>> re.compile('ing$').findall('I am falling in code', 2, 12) 
    ['ing'] # ing is the ending 
    >>> re.compile('ing$').findall('I am falling in code'[2:12]) 
    ['ing'] # ing is the ending 

    >>> re.compile('(?<=)am').findall('I am falling in code', 2, 12) 
    ['am'] # before am there is a space 
    >>> re.compile('(?<=)am').findall('I am falling in code'[2:12]) 
    []  # before am there is no space 
    >>> re.compile('ing(?=)').findall('I am falling in code', 2, 12) 
    []  # after ing there is no space 
    >>> re.compile('ing(?=)').findall('I am falling in code'[2:12]) 
    []  # after ing there is no space 

    >>> re.compile(r'\bm.....').findall('I am falling in code', 3, 11) 
    [] 
    >>> re.compile(r'\bm.....').findall('I am falling in code'[3:11]) 
    ['m fall'] 
    >>> re.compile(r'.....n\b').findall('I am falling in code', 3, 11) 
    ['fallin'] 
    >>> re.compile(r'.....n\b').findall('I am falling in code'[3:11]) 
    ['fallin'] 

Meine Fragen sind ... Warum ist es nicht konsistent zwischen und beginnen Spiel zu beenden? Warum behandelt die Verwendung von pos und endpos das Ende als das echte Ende, aber der Start/Anfang wird nicht als der echte Start/Anfang behandelt?

Gibt es einen Ansatz zur Verwendung von pos und endpos imitieren schneiden? Da Python copies string when slicing nicht nur die alte referenziert, wäre es effizienter, pos und endpos anstelle von Slicing zu verwenden, wenn mit großen Strings mehrere Male gearbeitet wird.

+1

Sehr seltsam scheint es, dass das neue Regex-Modul das gleiche Verhalten hat. –

+4

Es sieht einen Fehlerbericht nach Python: http://bugs.python.org/ –

+1

@ArminRigo Aber die Dokumentation sagte es, so könnte es ein "Feature" sein :) – BornToCode

Antwort

0

Dies klingt wie ein Fehler in Python, aber wenn Sie Slice by Referenz statt Kopieren der Zeichenfolgen tun möchten, können Sie das eingebaute Python buffer verwenden.

Zum Beispiel:

s = "long string" * 100 
buf = buffer(s) 
substr = buf([5:15]) 

Dieses eine Teil erstellt, ohne die Daten zu kopieren, so sollte für eine effiziente Aufteilung großer Strings ermöglichen.

+0

Schöne Infos über 'buffer', leider ist es in Python 3 nicht verfügbar. – BornToCode

+1

@BornToCode: Leider ist es mir nicht gelungen, den Python3-Ersatz' memoryview' mit String-Slices richtig zu arbeiten. Ich dachte, ich würde den Puffer trotzdem erwähnen, weil es immer noch viele Python2-Benutzer gibt und die Frage keine Version spezifiziert hat. –

+0

Ich würde vorsichtig sein, Annahmen über die Beziehung zwischen Zeichenfolgen und Puffern zu machen. Letztere sind beide byte-orientiert, während Strings (und Regexes) vor allem in Python3 mit vollem Unicode arbeiten. Das Slice 's [2: 4]' bezieht sich also auf zwei * Zeichen *, sie können jedoch auch als 3 bis 6 * Bytes dargestellt werden. Das bedeutet, dass Sie vorsichtig sein müssen, wenn Sie annehmen, dass Sie rohe Speicheroperationen für Strings ausführen können. Dies legt nahe, dass das ursprüngliche Poster das Gesamtbild ein wenig mehr berücksichtigen sollte und eine algorithmische Lösung in Erwägung ziehen sollte, anstatt zu tief in die Mikroeffizienz von Python-Code einzutauchen. –

1

Das Startpositionsargument pos ist besonders nützlich, um beispielsweise lexikalische Analysatoren zu erstellen. Der Leistungsunterschied zwischen dem Schneiden eines Strings mit [pos:] und dem Verwenden des Parameters pos mag unbedeutend erscheinen, ist aber sicherlich nicht so; siehe zum Beispiel diesen Fehlerbericht in der JsLex lexer.

In der Tat stimmt die ^ am tatsächlichen Anfang der Zeichenfolge; oder, wenn MULTILINE angegeben ist, auch am Anfang der Zeile; Dies ist auch von Entwurf, so dass ein Scanner auf regulären Ausdrücken zwischen real Anfang der Zeile/Beginn der Eingabe und nur ein anderer Punkt auf einer Linie/innerhalb der Eingabe leicht unterscheiden kann.

Sie beachten Sie, dass Sie auch die regex.match(string[, pos[, endpos]]) Funktion können Sie das Spiel auf die beginnende Zeichenfolge oder an der Position von pos angegeben zu verankern; so zu tun, anstatt

>>> re.compile('^am').findall('I am falling in code', 2, 12) 
[] 

Sie würden im Allgemeinen einen Scanner als

>>> match = re.compile('am').match('I am falling in code', 2, 12) 
>>> match 
<_sre.SRE_Match object; span=(2, 4), match='am'> 

implementieren und dann die pos zu match.end() für die aufeinanderfolgenden Anpassungsvorgänge (die in diesem Fall 4 zurückgibt).

Das Spiel muss beginnen genau am pos finden:

(Beachten Sie, wie die .match am Anfang des Eingangs verankert ist, als ob durch implizite ^ aber nicht bis zum Ende des Eingangs, ja dies ist oft eine Quelle von Fehlern, wie Menschen das Spiel glauben sowohl implizite ^ und $ - Python 3.4 hinzugefügt, um die regex.fullmatch, das dies tut)


Warum der endpos Parameter ist nicht konsistent mit dem pos - das weiß ich nicht genau, aber es macht auch einen Sinn für mich, wie in Python 2 gibt es keine fullmatch und dort Verankerung mit $ ist die einzige Möglichkeit zu gewährleisten dass die gesamte Spannweite angepasst werden muss.

Verwandte Themen