Comment obtenir tout avant un: dans une chaîne Python

102

Je cherche un moyen d'obtenir toutes les lettres dans une chaîne avant a: mais je ne sais pas par où commencer. Est-ce que j'utiliserais regex? Si c'est le cas, comment?

string = "Username: How are you today?"

Quelqu'un peut-il me montrer un exemple de ce que je pourrais faire?

0Cool
la source

Réponses:

169

Utilisez simplement la splitfonction. Il renvoie une liste, vous pouvez donc conserver le premier élément:

>>> s1.split(':')
['Username', ' How are you today?']
>>> s1.split(':')[0]
'Username'
Fredtantini
la source
12
Soit limiter le partage, soit dans ce cas - utilisers1.partition(':')[0]
Jon Clements
Merci, c'était très utile et instructif. De plus, c'est une grande aide merci!
0Cool
1
N'utilisez pas split, car il traite tous les ':' et crée un tableau complet, ce qui n'est pas bon pour les chaînes plus longues. Voir l'approche de @ Hackaholic pour utiliser un index. Juste celui-là recommande également une regex qui n'est clairement pas aussi efficace. Il doit également y avoir une option python pour effectuer l'opération standard de .substringBefore () qui est basée sur un index. Et aussi des variantes comme .substringBeforeLast (), etc. devraient être là pour plus de commodité (le code ne devrait pas être répété). Remarqué le point sur la partition - oui, moins de traitement après le ':', mais retourne toujours <class 'tuple'>: ('1', ':', '2: 3') plutôt que '1'.
arntg le
43

Utilisation index:

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

L'index vous donnera la position de :dans la chaîne, puis vous pourrez la découper.

Si vous souhaitez utiliser regex:

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

match correspond au début de la chaîne.

vous pouvez aussi utiliser itertools.takewhile

>>> import itertools
>>> "".join(itertools.takewhile(lambda x: x!=":", string))
'Username'
Hackaholic
la source
3
Cette méthode (string [: string.index (":")]) est probablement plus propre que le split
Damien
Pour la vitesse, n'utilisez pas de regex - utilisez la première option d'index mentionnée ici. Regex n'est clairement pas aussi efficace. Il doit également y avoir une option python pour effectuer l'opération standard de .substringBefore () qui est basée sur un index. Et aussi des variantes comme .substringBeforeLast (), etc. devraient être là pour plus de commodité (le code ne devrait pas être répété). Suggérez de mettre à jour cette réponse pour expliquer pourquoi l'indice fonctionne mieux et pourquoi cela devrait être utilisé par rapport à d'autres approches, y compris celle qui a voté plus haut maintenant dans la réponse de fredtantini.
arntg le
S'il n'est pas présent, l'index échouera.
Marc
18

Tu n'as pas besoin regexde ça

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

Vous pouvez utiliser la splitméthode pour diviser la chaîne sur le ':'caractère

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

Et découpez l'élément [0]pour obtenir la première partie de la chaîne

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

J'ai comparé ces différentes techniques sous Python 3.7.0 (IPython).

TLDR

  • le plus rapide (lorsque le symbole de scission cest connu): regex pré-compilée.
  • le plus rapide (autrement): s.partition(c)[0].
  • safe (c'est-à-dire, quand cpeut ne pas être dans s): partition, split.
  • unsafe: index, regex.

Code

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]

Résultats

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
la source
pourquoi considérez-vous que l' index n'est pas sûr?
James
2
s.index(c)déclenche une ValueError lorsqu'il cn'est pas dans s. Donc, je considère que c'est sûr quand je suis sûr que la chaîne à partitionner contient le séparateur, autrement dangereux.
Aristide
Pour index, c est dans s, donc ce n'est pas dangereux et toujours le plus rapide.
arntg le
2

partition () peut être mieux que split () à cette fin car il a les meilleurs résultats prévisibles pour les situations où vous n'avez pas de délimiteur ou plus de délimiteurs.

Marv-CZ
la source
1
Les deux partitionet splitfonctionneront de manière transparente avec une chaîne vide ou sans délimiteurs. Il est à noter que word[:word.index(':')]cela apparaîtra dans ces deux cas.
Rob Hall