Python Regex per trovare una stringa come un modello e il numero di rientro

Ho alcune linee che rappresentano alcuni dati in un file di testo. Sono tutti dei seguenti formati:

s = 'TheBears      SUCCESS Number of wins : 14'

Cominciano tutte con il nome, poi uno spazio vuoto e il testo ‘SUCCESSO certo Numero di vittorie :’ e, infine, il numero di vittorie, n1. Ci sono più stringhe ognuna con un nome diverso e di valore. Sto cercando di scrivere un programma in grado di analizzare una qualsiasi di queste stringhe e restituire il nome del set di dati, e il valore numerico alla fine della stringa. Sto cercando di utilizzare le espressioni regolari per fare questo e sono venuto su con il seguente:

import re
def winnumbers(s):
    pattern = re.compile(r"""(?P<name>.*?)     #starting name
                             \s*SUCCESS        #whitespace and success
                             \s*Number\s*of\s*wins  #whitespace and strings
                             \s*\:\s*(?P<n1>.*?)""",re.VERBOSE)
    match = pattern.match(s)

    name = match.group("name")
    n1 = match.group("n1")

    return (name, n1)

Finora, il mio programma in grado di restituire il nome, ma il problema viene dopo. Tutti hanno il testo “il SUCCESSO del maggior Numero di vittorie :” quindi il mio pensiero era quello di trovare un modo per corrispondere a questo testo. Ma mi rendo conto che il mio metodo di matching esatto sottostringa non è corretto adesso. C’è un modo per corrispondere a tutta la sottostringa come parte del modello? Ho letto un po ‘ su espressioni regolari ultimamente ma non ho trovato niente di simile. Sono ancora molto nuovo per la programmazione e apprezzo qualsiasi tipo di assistenza.

Alla fine, io uso il galleggiante() per tornare n1 come un numero, ma ho lasciato perché non individuare correttamente il numero, in primo luogo, ora e solo restituisce un errore.

Il tuo problema è l’uso del .*? alla fine dell’espressione regolare. Il ? rendono pigri, il che significa che non sarà del match con pochi personaggi possibili, quindi se si termina una regex con .*? non corrisponde a tutti i caratteri. O sbarazzarsi di ? per il tuo n1 gruppo o aggiungere un $ alla fine dell’espressione regolare in modo che si sarà costretti a corrispondere alla fine della riga.
Rimozione ? alla fine del n1 gruppo ha fatto il trucco! Vi ringrazio molto. Dovrò tenere a mente e di essere più attenti che da ora in poi.

OriginaleL’autore Simos Anderson | 2011-06-16

3 Replies
  1. 2

    Provare questo fuori:

    ((\S+)\s+SUCCESS Number of wins : (\d+))

    Questi sono i risultati:

    >>> regex = re.compile("((\S+)\s+SUCCESS Number of wins : (\d+))")
    >>> r = regex.search(string)
    >>> r
    <_sre.SRE_Match object at 0xc827cf478a56b350>
    >>> regex.match(string)
    <_sre.SRE_Match object at 0xc827cf478a56b228>
    
    # List the groups found
    >>> r.groups()
    (u'TheBears SUCCESS Number of wins : 14', u'TheBears', u'14')
    
    # List the named dictionary objects found
    >>> r.groupdict()
    {}
    
    # Run findall
    >>> regex.findall(string)
    [(u'TheBears SUCCESS Number of wins : 14', u'TheBears', u'14')]
    # So you can do this for the name and number:
    >>> fullstring, name, number = r.groups()

    Se non ti serve la stringa completa, è sufficiente rimuovere il surround parentesi.

    OriginaleL’autore

  2. 2

    Credo che non vi è alcuna reale necessità di usare una regex qui. Quindi, è possibile utilizzare il codice riportato di seguito se è accettabile per voi(nota che l’ho postato così si avrà la possibilità di avere un’altra opzione):

    dict((line[:line.lower().index('success')+1], line[line.lower().index('wins:') + 6:]) for line in text.split('\n') if 'success' in line.lower())

    O nel caso di voi sono sicuro che tutte le parole sono divisi da spazi:

    output={}
    for line in text:
        if 'success' in line.lower():
            words = line.strip().split(' ')
            output[words[0]] = words[-1]
    +1 per la quasi illeggibile one-liner 😉
    Aggiunto leggibile soluzione))

    OriginaleL’autore

  3. 1

    Se il testo in mezzo è sempre costante, non c’è bisogno di un’espressione regolare. Integrato stringa di funzioni di elaborazione sarà più efficiente e più facile lo sviluppo, il debug e la manutenzione. In questo caso, si può semplicemente utilizzare l’integrato split() funzione per ottenere i pezzi, e poi pulire il due pezzi come appropriato:

    >>> def winnumber(s):
    ...     parts = s.split('SUCCESS Number of wins : ')
    ...     return (parts[0].strip(), int(parts[1]))
    ... 
    >>> winnumber('TheBears      SUCCESS Number of wins : 14')
    ('TheBears', 14)

    Nota che ho in output il numero di vittorie, come un numero intero (come presumibilmente questo sarà sempre un numero intero), ma si può facilmente sostituire float()– o qualsiasi altra funzione di conversione – per int(), se lo desideri.

    Modifica: Ovviamente questo funziona solo per singole linee – se si chiama la funzione con diverse linee deve dare errori. La trasformazione di un intero file, mi piacerebbe usare il map():

    >>> map(winnumber, open(filename, 'r'))
    [('TheBears', 14), ('OtherTeam', 6)]

    Inoltre, non sono sicuro del tuo utilizzo di questo codice, ma si potrebbe trovare più facile lavorare con le uscite di un dizionario:

    >>> dict(map(winnumber, open(filename, 'r')))
    {'OtherTeam': 6, 'TheBears': 14}

    OriginaleL’autore

Lascia un commento