Come potrei ottenere tutto prima di a: in una stringa Python


102

Sto cercando un modo per inserire tutte le lettere in una stringa prima di a: ma non ho idea di dove iniziare. Userei regex? Se é cosi, come?

string = "Username: How are you today?"

Qualcuno può mostrarmi un esempio su quello che potrei fare?

Risposte:


169

Usa la splitfunzione. Restituisce un elenco, quindi puoi mantenere il primo elemento:

>>> s1.split(':')
['Username', ' How are you today?']
>>> s1.split(':')[0]
'Username'

12
O limita la divisione o, in questo caso, usas1.partition(':')[0]
Jon Clements

Grazie, questo è stato molto utile e informativo. Inoltre è stato un grande aiuto grazie!
Cool

1
Non utilizzare split, poiché elabora tutti i caratteri ":" e crea un array completo, non adatto per stringhe più lunghe. Vedi l'approccio di @ Hackaholic per usare un indice. Solo quello sta anche raccomandando una regex che chiaramente non è altrettanto efficace. Inoltre deve esserci un'opzione python per eseguire l'operazione standard di .substringBefore () che è basata sull'indice. E anche variazioni come .substringBeforeLast (), ecc. Dovrebbero essere lì per comodità (il codice non dovrebbe essere ripetuto). Ho notato il punto sulla partizione: sì, meno elaborazione dopo ':', ma restituisce ancora <class 'tuple'>: ('1', ':', '2: 3') invece di '1'.
arntg

43

Utilizzando index:

>>> string = "Username: How are you today?"
>>> string[:string.index(":")]
'Username'

L'indice ti darà la posizione di :in string, quindi puoi tagliarlo.

Se vuoi usare regex:

>>> import re
>>> re.match("(.*?):",string).group()
'Username'                       

match corrisponde dall'inizio della stringa.

puoi anche usare itertools.takewhile

>>> import itertools
>>> "".join(itertools.takewhile(lambda x: x!=":", string))
'Username'

3
Questo metodo (string [: string.index (":")]) è probabilmente più pulito della divisione
Damien

Per la velocità non utilizzare regex: usa la prima opzione di indice menzionata qui. Le espressioni regolari chiaramente non sono altrettanto efficaci. Inoltre deve esserci un'opzione python per eseguire l'operazione standard di .substringBefore () che è basata sull'indice. E anche variazioni come .substringBeforeLast (), ecc. Dovrebbero essere lì per comodità (il codice non dovrebbe essere ripetuto). Suggerisci di aggiornare questa risposta per spiegare perché l'indice funziona meglio e quindi perché questo dovrebbe essere utilizzato su altri approcci, incluso quello votato più in alto ora nella risposta di fredtantini.
arntg

Se non è presente, l'indice fallirà.
Marc

18

Non hai bisogno regexdi questo

>>> s = "Username: How are you today?"

Puoi utilizzare il splitmetodo per dividere la stringa sul ':'carattere

>>> s.split(':')
['Username', ' How are you today?']

E tagliare l'elemento [0]per ottenere la prima parte della stringa

>>> s.split(':')[0]
'Username'

7

Ho confrontato queste varie tecniche con Python 3.7.0 (IPython).

TLDR

  • più veloce (quando il simbolo di divisione cè noto): regex precompilato.
  • più veloce (altrimenti): s.partition(c)[0].
  • sicuro (cioè, quando cpotrebbe non essere presente s): partizione, suddivisione.
  • unsafe: index, regex.

Codice

import string, random, re

SYMBOLS = string.ascii_uppercase + string.digits
SIZE = 100

def create_test_set(string_length):
    for _ in range(SIZE):
        random_string = ''.join(random.choices(SYMBOLS, k=string_length))
        yield (random.choice(random_string), random_string)

for string_length in (2**4, 2**8, 2**16, 2**32):
    print("\nString length:", string_length)
    print("  regex (compiled):", end=" ")
    test_set_for_regex = ((re.compile("(.*?)" + c).match, s) for (c, s) in test_set)
    %timeit [re_match(s).group() for (re_match, s) in test_set_for_regex]
    test_set = list(create_test_set(16))
    print("  partition:       ", end=" ")
    %timeit [s.partition(c)[0] for (c, s) in test_set]
    print("  index:           ", end=" ")
    %timeit [s[:s.index(c)] for (c, s) in test_set]
    print("  split (limited): ", end=" ")
    %timeit [s.split(c, 1)[0] for (c, s) in test_set]
    print("  split:           ", end=" ")
    %timeit [s.split(c)[0] for (c, s) in test_set]
    print("  regex:           ", end=" ")
    %timeit [re.match("(.*?)" + c, s).group() for (c, s) in test_set]

Risultati

String length: 16
  regex (compiled): 156 ns ± 4.41 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
  partition:        19.3 µs ± 430 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
  index:            26.1 µs ± 341 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
  split (limited):  26.8 µs ± 1.26 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
  split:            26.3 µs ± 835 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
  regex:            128 µs ± 4.02 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

String length: 256
  regex (compiled): 167 ns ± 2.7 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
  partition:        20.9 µs ± 694 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
  index:            28.6 µs ± 2.73 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
  split (limited):  27.4 µs ± 979 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
  split:            31.5 µs ± 4.86 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
  regex:            148 µs ± 7.05 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

String length: 65536
  regex (compiled): 173 ns ± 3.95 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
  partition:        20.9 µs ± 613 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
  index:            27.7 µs ± 515 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
  split (limited):  27.2 µs ± 796 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
  split:            26.5 µs ± 377 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
  regex:            128 µs ± 1.5 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

String length: 4294967296
  regex (compiled): 165 ns ± 1.2 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
  partition:        19.9 µs ± 144 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
  index:            27.7 µs ± 571 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
  split (limited):  26.1 µs ± 472 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
  split:            28.1 µs ± 1.69 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
  regex:            137 µs ± 6.53 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

perché ritieni che l' indice non sia sicuro?
James

2
s.index(c)solleva un'eccezione ValueError quando cnon è in s. Quindi, lo considero sicuro quando sono sicuro che la stringa da partizionare contiene il separatore, altrimenti non sicuro.
Aristide

Per index, c è in s, quindi non è pericoloso e comunque più veloce.
arntg

2

partition () potrebbe essere migliore di split () per questo scopo in quanto ha i migliori risultati prevedibili per situazioni in cui non hai delimitatori o più delimitatori.


1
Entrambi partitione splitfunzioneranno in modo trasparente con una stringa vuota o senza delimitatori. Vale la pena notare che word[:word.index(':')]apparirà in entrambi i casi.
Rob Hall,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.