Frage

Lassen Sie uns sagen, ich habe teh folgende:

  

{{Hallo | Hallo | Hey} {welt | Erde} |   {Auf Wiedersehen | Abschied} {noobs | n3wbz | n00blets}}

Und ich möchte, dass in einer der folgenden Eigenschaften aktivieren:

Hello world 
Goodbye noobs 
Hi earth
farewell n3wbz 
// etc.

Aufmerksamkeit auf die Art und Weise der „spinning“ Syntax verschachtelt ist. Es könnte eine Milliarde Schichten tief für alle verschachtelt werden wir wissen.

Ich kann das einfach tun, außer, wenn sie wie im obigen Beispiel verschachtelt sind meine regex vermasseln und die Ergebnisse sind nicht korrekt.

Könnte jemand zeigt ein Beispiel entweder in einer .NET-Sprache oder Python bitte?

War es hilfreich?

Lösung

Eine einfache Art und Weise mit re.subn , die auch eine Funktion anstelle einer Ersatzzeichenfolge akzeptieren können:

import re
from random import randint

def select(m):
    choices = m.group(1).split('|')
    return choices[randint(0, len(choices)-1)]

def spinner(s):
    r = re.compile('{([^{}]*)}')
    while True:
        s, n = r.subn(select, s)
        if n == 0: break
    return s.strip()

Es ist einfach ersetzt die tiefste Entscheidungen er trifft, dann iteriert, bis keine andere Wahl bleibt. subn gibt ein Tupel mit dem Ergebnis, und wie viele Ersetzungen vorgenommen wurden, was sehr praktisch ist das Ende der Verarbeitung zu erkennen.

Meine Version von select() kann durch bobince denen ersetzt werden, die random.choice() verwenden und sind eleganter, wenn man nur auf einen zufälligen Wähler halten will. Wenn Sie die Wahl Baum bauen möchten, können Sie die obige Funktion erweitern, aber Sie werden globale Variablen brauchen, um zu verfolgen, wo Sie sind, so die Funktionen in eine Klasse bewegen würde Sinn machen. Dies ist nur ein Hinweis, ich will nicht, dass die Idee entwickeln, da es nicht wirklich die orginial Frage war.

Beachten Sie schließlich, dass Sie r.subn(select, s, re.U) verwenden sollten, wenn Sie Unicode-Strings (s = u"{...}")

brauchen

Beispiel:

>>> s = "{{Hello|Hi|Hey} {world|earth} | {Goodbye|farewell} {noobs|n3wbz|n00blets}}"
>>> print spinner(s)
'farewell n3wbz'

Edit: ersetzt sub durch subn Endlosschleife (dank bobince es, darauf hinzuweisen) zu vermeiden und machen sie effizienter und ersetzt {([^{}]+)} durch {([^{}]*)} leere geschweifte Klammern als auch zu extrahieren. Das sollte es robuster zu schlecht formatierten Muster.

Für Menschen, die so viel wie möglich zu setzen wie auf einer Linie (die ich persönlich würde nicht fördern):

def spin(s):
    while True:
        s, n = re.subn('{([^{}]*)}',
                       lambda m: random.choice(m.group(1).split("|")),
                       s)
        if n == 0: break
    return s.strip()

Andere Tipps

Sollte ziemlich einfach sein, nur eine Klammer nicht zuläßt aus mit einem anderen Satz, dann ruft immer wieder Ersatz von den inneren Streichhölzern dabei nach außen:

def replacebrace(match):
    return random.choice(match.group(1).split('|'))

def randomizebraces(s):
   while True:
       s1= re.sub(r'\{([^{}]*)\}', replacebrace, s)
       if s1==s:
           return s
       s= s1

>>> randomizebraces('{{Hello|Hi|Hey} {world|earth}|{Goodbye|farewell} {noobs|n3wbz|n00blets}}')
'Hey world'
>>> randomizebraces('{{Hello|Hi|Hey} {world|earth}|{Goodbye|farewell} {noobs|n3wbz|n00blets}}')
'Goodbye noobs'

Diese regex Inverter verwendet pyparsing erzeugen Strings (mit einigen Einschränkungen - unbegrenzte Wiederholung Symbole wie + und * sind nicht erlaubt) entsprechen. Wenn Sie ersetzen {} s mit () 's Ihre ursprünglichen Zeichenfolge in einen regulären Ausdruck zu machen, erzeugt der Wechselrichter diese Liste:

Helloworld
Helloearth
Hiworld
Hiearth
Heyworld
Heyearth
Goodbyenoobs
Goodbyen3wbz
Goodbyen00blets
farewellnoobs
farewelln3wbz
farewelln00blets

(Ich weiß, dass die Räume sind zusammengebrochen, aber vielleicht wird dieser Code gibt Ihnen einige Ideen, wie man dieses Problem attackieren.)

würde ich re.finditer verwenden und einen grundlegenden Parsing-Baum bauen, um die Verschachtelung Ebene zu bestimmen. Um es zu machen, würde ich die Spanne Attribut des Regex-Objekts verwenden:

text = '{{Hello|Hi|Hey} {world|earth} | {Goodbye|farewell} {noobs|n3wbz|n00blets}}'

import re
re_bracks = re.compile(r'{.+?}')

# subclass list for a basic tree datatype
class bracks(list):
    def __init__(self, m):
        self.m = m

# icky procedure to create the parse tree
# I hate these but don't know how else to do it
parse_tree = []
for m in re_bracks.finditer(text):
    if not this_element:
        # this first match
        parse_tree.extend(element(m))
    else:
        # ... and all the rest
        this_element = bracks(m)
        this_start, this_end = m.span()

        # if this match is nested in the old one ...
        if this_start < previous_start and this_end > previous_end:
            # nest it inside the previous one
            previous_element.extend(this_element) 
        else:
            # otherwise make it a child of the parse_tree
            parse_tree.extend(element(m))

        previous_element = this_element
        previous_start, previous_end = this_start, this_end

Dies würde die Schachtelungstiefe der Klammerausdrücke geben. Fügen Sie einige ähnliche Logik für die Rohre und Sie würden gut auf dem Weg, das Problem zu lösen.

Ich würde empfehlen, einen Blick auf der dada Motor für Inspiration nehmen.

Ich habe eine Implementierung von etwas durch das in Schema inspiriert getan und AST Leveraged Schema meine Bedürfnisse auszudrücken.

Insbesondere würde ich empfehlen dringend davor, einen regulären Ausdruck als Parser im Allgemeinen zu verwenden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top