Como eu obteria tudo antes de um: em uma string Python

102

Estou procurando uma maneira de obter todas as letras de uma string antes de a: mas não tenho ideia de por onde começar. Eu usaria regex? Se sim, como?

string = "Username: How are you today?"

Alguém pode me mostrar um exemplo do que eu poderia fazer?

0Cool
fonte

Respostas:

169

Basta usar a splitfunção. Ele retorna uma lista, então você pode manter o primeiro elemento:

>>> s1.split(':')
['Username', ' How are you today?']
>>> s1.split(':')[0]
'Username'
Fredtantini
fonte
12
Ou limitar a separação, ou neste caso - usos1.partition(':')[0]
Jon Clements
Obrigado, isso foi muito útil e informativo. Além disso, foi uma grande ajuda, obrigado!
0Cool
1
Não use split, pois ele está processando todos os ':' e cria um array completo, não é bom para strings mais longas. Consulte a abordagem de @Hackaholic para usar um índice. Apenas aquele também está recomendando uma regex que claramente não é tão eficaz. Também deve haver uma opção python para fazer a operação padrão de .substringBefore () que é baseada em índice. E também variações como .substringBeforeLast (), etc. devem estar lá por conveniência (o código não deve ser repetido). Percebi o ponto sobre a partição - sim, menos processamento após ':', mas ainda retorna <class 'tuple'>: ('1', ':', '2: 3') em vez de '1'.
arntg
43

Usando index:

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

O índice dará a você a posição da :string, então você pode cortá-la.

Se você deseja usar regex:

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

match corresponde desde o início da string.

você também pode usar itertools.takewhile

>>> import itertools
>>> "".join(itertools.takewhile(lambda x: x!=":", string))
'Username'
Hackaholic
fonte
3
Este método (string [: string.index (":")]) é provavelmente mais limpo do que a divisão
Damien
Para velocidade, não use regex - use a primeira opção de índice mencionada aqui. Regex claramente não é tão eficaz. Também deve haver uma opção python para fazer a operação padrão de .substringBefore () que é baseada em índice. E também variações como .substringBeforeLast (), etc. devem estar lá por conveniência (o código não deve ser repetido). Sugira atualizar esta resposta para explicar por que o índice funciona melhor e, então, por que ele deve ser usado em relação a outras abordagens, incluindo aquela que está votada acima agora na resposta de fredtantini.
arntg
Se não estiver presente, o índice falhará.
Marc
18

Você não precisa regexdisso

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

Você pode usar o splitmétodo para dividir a string no ':'caractere

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

E corte o elemento [0]para obter a primeira parte da string

>>> s.split(':')[0]
'Username'
Cory Kramer
fonte
7

Eu comparei essas várias técnicas em Python 3.7.0 (IPython).

TLDR

  • mais rápido (quando o símbolo de divisão cé conhecido): regex pré-compilado.
  • mais rápido (não): s.partition(c)[0].
  • seguro (ou seja, quando cpode não estar em s): partição, divisão.
  • inseguro: índice, regex.

Código

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]

Resultados

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
fonte
por que você considera o índice inseguro?
James
2
s.index(c)gera um ValueError quando cnão está em s. Portanto, considero seguro quando tenho certeza de que a string a ser particionada contém o separador, caso contrário, inseguro.
Aristide
Para índice, c está em s, portanto, não é inseguro e ainda mais rápido.
arntg
2

partition () pode ser melhor do que split () para esse propósito, pois tem os melhores resultados previsíveis para situações em que você não tem delimitador ou mais delimitadores.

Marv-CZ
fonte
1
Ambos partitione splitfuncionarão de forma transparente com uma string vazia ou sem delimitadores. É importante notar que word[:word.index(':')]aparecerá em ambos os casos.
Rob Hall