Как мне получить все до: в строке Python

107

Я ищу способ получить все буквы в строке перед: но я не знаю, с чего начать. Могу ли я использовать регулярное выражение? Если да, то как?

string = "Username: How are you today?"

Может кто-нибудь показать мне пример того, что я могу сделать?

0 Прохладный
источник

Ответы:

181

Просто воспользуйтесь splitфункцией. Он возвращает список, поэтому вы можете оставить первый элемент:

>>> s1.split(':')
['Username', ' How are you today?']
>>> s1.split(':')[0]
'Username'
Фредтантини
источник
12
Либо ограничьте сплит, либо в данном случае - используйтеs1.partition(':')[0]
Джон Клементс
Спасибо, это было очень полезно и информативно. Плюс это большая помощь, спасибо!
0Cool
2
Не используйте split, поскольку он обрабатывает все символы ':' и создает полный массив, что не подходит для более длинных строк. См. Подход @Hackaholic к использованию индекса. Просто он также рекомендует регулярное выражение, которое явно не так эффективно. Также должна быть опция python для выполнения стандартной операции .substringBefore (), основанной на индексе. А также для удобства должны быть такие варианты, как .substringBeforeLast () и т.д. (код не должен повторяться). Заметил момент о разделении - да, меньше обработки после ':', но по-прежнему возвращает <class 'tuple'>: ('1', ':', '2: 3'), а не '1'.
arntg
48

Использование index:

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

Индекс даст вам позицию :в строке, после чего вы можете ее разрезать.

Если вы хотите использовать регулярное выражение:

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

match соответствует с начала строки.

вы также можете использовать itertools.takewhile

>>> import itertools
>>> "".join(itertools.takewhile(lambda x: x!=":", string))
'Username'
Хакоголик
источник
3
Этот метод (string [: string.index (":")]), вероятно, чище, чем split
Дэмиен
Для скорости не используйте регулярное выражение - используйте первую упомянутую здесь опцию индекса. Regex явно не так эффективен. Также должна быть опция python для выполнения стандартной операции .substringBefore (), основанной на индексе. А также для удобства должны быть такие варианты, как .substringBeforeLast () и т.д. (код не должен повторяться). Предложите обновить этот ответ, чтобы объяснить, почему индекс работает лучше, а затем, почему его следует использовать по сравнению с другими подходами, включая тот, за который в ответе Фредтантини проголосовали выше.
arntg
Если его нет, индекс не удастся.
Марк
19

Вам не нужно regexдля этого

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

Вы можете использовать этот splitметод для разделения строки на ':'символ

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

И вырежьте элемент, [0]чтобы получить первую часть строки

>>> s.split(':')[0]
'Username'
Кори Крамер
источник
9

Я протестировал эти различные методы в Python 3.7.0 (IPython).

TL; DR

  • самый быстрый (когда cизвестен символ разделения ): предварительно скомпилированное регулярное выражение.
  • Самый быстрый ( в противном случае) s.partition(c)[0].
  • безопасно (т.е. когда cможет не быть внутри s): раздел, разделение.
  • небезопасно: индекс, регулярное выражение.

Код

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]

Полученные результаты

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)
Аристид
источник
1
почему вы считаете индексирование небезопасным?
Джеймс
3
s.index(c)вызывает ValueError, когда cне находится внутри s. Таким образом, я считаю безопасным, когда я уверен, что разделяемая строка содержит разделитель, в противном случае небезопасно.
Аристид
1
Для index c находится в s, поэтому это небезопасно и все же самое быстрое.
arntg
3

Для этой цели partition () может быть лучше, чем split (), поскольку он дает лучшие предсказуемые результаты в ситуациях, когда у вас нет разделителя или большего количества разделителей.

Marv-CZ
источник
1
Оба partitionи splitбудут работать прозрачно с пустой строкой или без разделителей. Стоит отметить, что word[:word.index(':')]лопнет в обоих этих случаях.
Роб Холл,