¿Cómo obtendría todo antes de un: en una cadena de Python

107

Estoy buscando una forma de obtener todas las letras en una cadena antes de a: pero no tengo idea de por dónde empezar. ¿Usaría expresiones regulares? ¿Si es así, cómo?

string = "Username: How are you today?"

¿Alguien puede mostrarme un ejemplo de lo que podría hacer?

0 Genial
fuente

Respuestas:

181

Solo usa la splitfunción. Devuelve una lista, por lo que puede conservar el primer elemento:

>>> s1.split(':')
['Username', ' How are you today?']
>>> s1.split(':')[0]
'Username'
Fredtantini
fuente
12
O bien limitar la separación, o en este caso - usos1.partition(':')[0]
Jon Clements
Gracias, esto fue muy útil e informativo. Además, fue una gran ayuda, ¡gracias!
0Cool
2
No use split, ya que está procesando todos los ':' y crea una matriz completa, no es bueno para cadenas más largas. Vea el enfoque de @ Hackaholic para usar un índice. Solo ese también está recomendando una expresión regular que claramente no es tan efectiva. También tiene que haber una opción de Python para realizar la operación estándar de .substringBefore () que se basa en índices. Y también variaciones como .substringBeforeLast (), etc. deberían estar ahí por conveniencia (el código no debe repetirse). Noté el punto sobre la partición: sí, menos procesamiento después de ':', pero aún así devuelve <class 'tuple'>: ('1', ':', '2: 3') en lugar de '1'.
hasta el
48

Usando index:

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

El índice le dará la posición de :en cadena, luego puede cortarlo.

Si desea utilizar expresiones regulares:

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

match coincide con el inicio de la cadena.

también puedes usar itertools.takewhile

>>> import itertools
>>> "".join(itertools.takewhile(lambda x: x!=":", string))
'Username'
Hackaholic
fuente
3
Este método (string [: string.index (":")]) es probablemente más limpio que el split
Damien
Para mayor velocidad, no use expresiones regulares: use la primera opción de índice mencionada aquí. Regex claramente no es tan efectivo. También tiene que haber una opción de Python para realizar la operación estándar de .substringBefore () que se basa en índices. Y también variaciones como .substringBeforeLast (), etc. deberían estar ahí por conveniencia (el código no debe repetirse). Sugiera actualizar esta respuesta para explicar por qué el índice funciona mejor y luego por qué debería usarse sobre otros enfoques, incluido el que se votó más alto ahora en la respuesta de fredtantini.
arntg
Si no está presente, el índice fallará.
Marc
19

No necesitas regexpara esto

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

Puede usar el splitmétodo para dividir la cadena en el ':'carácter

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

Y corta el elemento [0]para obtener la primera parte de la cadena.

>>> s.split(':')[0]
'Username'
Cory Kramer
fuente
9

He comparado estas diversas técnicas en Python 3.7.0 (IPython).

TLDR

  • más rápido (cuando cse conoce el símbolo de división ): regex precompilado.
  • más rápido (de otra manera): s.partition(c)[0].
  • seguro (es decir, cuando cno puede estar en s): partición, división.
  • inseguro: índice, expresión regular.

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
fuente
1
¿Por qué considera que el índice no es seguro?
James
3
s.index(c)genera un ValueError cuando cno está en s. Por lo tanto, lo considero seguro cuando estoy seguro de que la cadena que se va a particionar contiene el separador; de lo contrario, no es seguro.
Aristide
1
Para el índice, c está en s, por lo que no es inseguro y aún más rápido.
hasta el
3

Partición () puede ser mejor que split () para este propósito, ya que tiene los mejores resultados predecibles para situaciones en las que no tiene delimitadores o tiene más delimitadores.

Marv-CZ
fuente
1
Ambos partitiony splitfuncionarán de forma transparente con una cadena vacía o sin delimitadores. Vale la pena señalar que word[:word.index(':')]aparecerá en ambos casos.
Rob Hall