Jak uzyskać wszystko przed: w łańcuchu Python

106

Szukam sposobu, aby uzyskać wszystkie litery w ciągu przed a:, ale nie mam pojęcia, od czego zacząć. Czy użyłbym wyrażenia regularnego? Jeśli tak to jak?

string = "Username: How are you today?"

Czy ktoś może pokazać mi przykład tego, co mogłem zrobić?

0 Cool
źródło

Odpowiedzi:

180

Po prostu użyj splitfunkcji. Zwraca listę, więc możesz zachować pierwszy element:

>>> s1.split(':')
['Username', ' How are you today?']
>>> s1.split(':')[0]
'Username'
fredtantini
źródło
12
Albo ogranicz podział, albo w tym przypadku - użyjs1.partition(':')[0]
Jon Clements
Dziękuję, to było bardzo przydatne i pouczające. Poza tym była to duża pomoc, dzięki!
Cool
2
Nie używaj split, ponieważ przetwarza wszystkie ':' i tworzy pełną tablicę, która nie jest dobra dla dłuższych łańcuchów. Zobacz podejście @ Hackaholic do korzystania z indeksu. Tyle tylko, że zaleca się również wyrażenie regularne, które wyraźnie nie jest tak skuteczne. Musi istnieć również opcja Pythona do wykonywania standardowej operacji .substringBefore (), która jest oparta na indeksach. Dla wygody powinny być dostępne również odmiany, takie jak .substringBeforeLast () itp. (Kod nie powinien być powtarzany). Zauważyłem kwestię dotyczącą partycji - tak, mniej przetwarzania po „:”, ale nadal zwraca <class 'tuple'>: ('1', ':', '2: 3') zamiast '1'.
arntg
47

Używając index:

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

Indeks poda pozycję :w ciągu, a następnie możesz go pokroić.

Jeśli chcesz użyć wyrażenia regularnego:

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

match dopasowuje od początku ciągu.

możesz także użyć itertools.takewhile

>>> import itertools
>>> "".join(itertools.takewhile(lambda x: x!=":", string))
'Username'
Hackaholic
źródło
3
Ta metoda (string [: string.index (":")]) jest prawdopodobnie czystsza niż podział
Damien
Dla szybkości nie używaj wyrażeń regularnych - użyj pierwszej wymienionej tutaj opcji indeksu. Regex najwyraźniej nie jest tak skuteczny. Musi istnieć również opcja Pythona do wykonania standardowej operacji .substringBefore (), która jest oparta na indeksach. Dla wygody powinny być dostępne również odmiany, takie jak .substringBeforeLast () itp. (Kod nie powinien być powtarzany). Zaproponuj zaktualizowanie tej odpowiedzi, aby wyjaśnić, dlaczego indeks działa lepiej, a następnie dlaczego należy go zastosować w stosunku do innych podejść, w tym do tego, który głosował wyżej w odpowiedzi fredtantiniego.
arntg
Jeśli go nie ma, indeks się nie powiedzie.
Marc
19

Nie potrzebujesz regextego

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

Możesz użyć tej splitmetody, aby podzielić ciąg znaków na ':'znak

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

I wytnij element, [0]aby uzyskać pierwszą część ciągu

>>> s.split(':')[0]
'Username'
Cory Kramer
źródło
8

Testowałem te różne techniki w Pythonie 3.7.0 (IPython).

TLDR

  • najszybszy (gdy cznany jest symbol podziału ): wstępnie skompilowane wyrażenie regularne.
  • najszybszy (inaczej) s.partition(c)[0].
  • safe (tj. kiedy cnie może być w s): partycja, podział.
  • niebezpieczne: index, regex.

Kod

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]

Wyniki

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)
Aristide
źródło
1
dlaczego uważasz, że indeksowanie jest niebezpieczne?
James
3
s.index(c)podnosi ValueError, gdy cnie ma go w s. Dlatego uważam to za bezpieczne, gdy mam pewność, że łańcuch do podzielenia na partycje zawiera separator, w przeciwnym razie jest niebezpieczny.
Aristide,
1
Dla indeksu c jest w s, więc nie jest to niebezpieczne i nadal jest najszybsze.
arntg
2

W tym celu metoda partition () może być lepsza niż split (), ponieważ daje lepsze przewidywalne wyniki w sytuacjach, w których nie ma ogranicznika lub jest ich więcej.

Marv-CZ
źródło
1
Oba partitioni splitbędą działać w sposób przezroczysty z pustym ciągiem lub bez separatorów. Warto zauważyć, że word[:word.index(':')]pojawi się w obu tych przypadkach.
Rob Hall