Wie würde ich alles vor einem: in einem String Python bekommen

100

Ich suche nach einer Möglichkeit, alle Buchstaben in einer Zeichenfolge vor a: zu erhalten, aber ich habe keine Ahnung, wo ich anfangen soll. Würde ich Regex verwenden? Wenn das so ist, wie?

string = "Username: How are you today?"

Kann mir jemand ein Beispiel zeigen, was ich tun könnte?

0Cool
quelle

Antworten:

165

Verwenden Sie einfach die splitFunktion. Es wird eine Liste zurückgegeben, sodass Sie das erste Element behalten können:

>>> s1.split(':')
['Username', ' How are you today?']
>>> s1.split(':')[0]
'Username'
Fredtantini
quelle
10
Entweder begrenzen die Spaltung, oder in diesem Fall - Verwendungs1.partition(':')[0]
Jon Clements
Vielen Dank, das war sehr nützlich und informativ. Außerdem war es eine große Hilfe, danke!
0Cool
1
Verwenden Sie nicht split, da es das gesamte ':' verarbeitet und ein vollständiges Array erstellt, das für längere Zeichenfolgen nicht geeignet ist. Siehe @ Hackaholic's Ansatz zur Verwendung eines Index. Nur dass man auch einen regulären Ausdruck empfiehlt, der eindeutig nicht so effektiv ist. Außerdem muss es eine Python-Option geben, um die Standardoperation von .substringBefore () auszuführen, die indexbasiert ist. Und auch Variationen wie .substringBeforeLast () usw. sollten der Einfachheit halber vorhanden sein (Code sollte nicht wiederholt werden). Bemerkte den Punkt über Partition - ja, weniger Verarbeitung nach dem ':', gibt aber immer noch <class 'tuple'>: ('1', ':', '2: 3') statt '1' zurück.
9.
41

Verwenden von index:

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

Der Index gibt Ihnen die Position :in der Zeichenfolge an, dann können Sie sie in Scheiben schneiden.

Wenn Sie Regex verwenden möchten:

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

match stimmt mit dem Anfang der Zeichenfolge überein.

Sie können auch verwenden itertools.takewhile

>>> import itertools
>>> "".join(itertools.takewhile(lambda x: x!=":", string))
'Username'
Hackaholic
quelle
3
Diese Methode (string [: string.index (":")]) ist wahrscheinlich sauberer als der Split
Damien
Verwenden Sie für die Geschwindigkeit keinen regulären Ausdruck - verwenden Sie die erste hier erwähnte Indexoption. Regex ist eindeutig nicht so effektiv. Außerdem muss es eine Python-Option geben, um die Standardoperation von .substringBefore () auszuführen, die indexbasiert ist. Und auch Variationen wie .substringBeforeLast () usw. sollten der Einfachheit halber vorhanden sein (Code sollte nicht wiederholt werden). Schlagen Sie vor, diese Antwort zu aktualisieren, um zu erklären, warum der Index besser funktioniert und warum dies gegenüber anderen Ansätzen verwendet werden sollte, einschließlich derjenigen, die jetzt in der Antwort von fredtantini höher gewählt wurden.
9.
Wenn es nicht vorhanden ist, schlägt der Index fehl.
Marc
18

Sie brauchen nicht regexfür diese

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

Mit dieser splitMethode können Sie die Zeichenfolge für das ':'Zeichen aufteilen

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

Und schneiden Sie das Element aus [0], um den ersten Teil der Zeichenfolge zu erhalten

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

Ich habe diese verschiedenen Techniken unter Python 3.7.0 (IPython) verglichen.

TLDR

  • am schnellsten (wenn das geteilte Symbol cbekannt ist): vorkompilierter Regex.
  • am schnellsten (sonst) : s.partition(c)[0].
  • sicher (dh wenn cnicht in s): Partition, aufgeteilt.
  • unsicher: 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]

Ergebnisse

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
quelle
Warum halten Sie Index für unsicher?
James
2
s.index(c)löst einen ValueError aus, wenn cnicht in s. Daher halte ich es für sicher, wenn ich sicher bin, dass die zu partitionierende Zeichenfolge das Trennzeichen enthält, ansonsten unsicher.
Aristide
Für den Index steht c in s, ist also nicht unsicher und immer noch am schnellsten.
9.
2

partition () ist zu diesem Zweck möglicherweise besser als split (), da es die besser vorhersehbaren Ergebnisse für Situationen liefert, in denen Sie kein Trennzeichen oder mehr Trennzeichen haben.

Marv-CZ
quelle
Beide partitionund splitarbeiten transparent mit einer leeren Zeichenfolge oder ohne Trennzeichen. Es ist erwähnenswert, dass dies word[:word.index(':')]in beiden Fällen der Fall sein wird.
Rob Hall