Bagaimana saya mendapatkan semuanya sebelum: dalam string Python


107

Saya mencari cara untuk mendapatkan semua huruf dalam string sebelum a: tapi saya tidak tahu harus mulai dari mana. Apakah saya akan menggunakan regex? Jika ya, bagaimana caranya?

string = "Username: How are you today?"

Dapatkah seseorang menunjukkan kepada saya contoh tentang apa yang dapat saya lakukan?

Jawaban:


181

Cukup gunakan splitfungsinya. Ini mengembalikan daftar, sehingga Anda dapat menyimpan elemen pertama:

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

12
Entah membatasi pemisahan, atau dalam kasus ini - gunakans1.partition(':')[0]
Jon Clements

Terima kasih, ini sangat berguna dan informatif. Ditambah itu bantuan besar terima kasih!
0Cool

2
Jangan gunakan split, karena itu memproses semua ':' dan membuat array penuh, tidak bagus untuk string yang lebih panjang. Lihat pendekatan @ Hackaholic untuk menggunakan indeks. Hanya saja yang satu ini juga merekomendasikan regex yang jelas tidak seefektif itu. Juga harus ada opsi python untuk melakukan operasi standar .substringBefore () yang berbasis indeks. Dan juga variasi seperti .substringBeforeLast (), dll harus ada untuk kenyamanan (kode tidak boleh diulang). Memperhatikan poin tentang partisi - ya, lebih sedikit pemrosesan setelah ':', tetapi masih mengembalikan <class 'tuple'>: ('1', ':', '2: 3') daripada '1'.
arntg

48

Menggunakan index:

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

Indeks akan memberi Anda posisi : dalam string, lalu Anda dapat mengirisnya.

Jika Anda ingin menggunakan regex:

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

match cocok dari awal string.

Anda juga bisa menggunakan itertools.takewhile

>>> import itertools
>>> "".join(itertools.takewhile(lambda x: x!=":", string))
'Username'

3
Metode ini (string [: string.index (":")]) mungkin lebih bersih daripada pemisahan
Damien

Untuk kecepatan, jangan gunakan regex - gunakan opsi indeks pertama yang disebutkan di sini. Regex jelas tidak efektif. Juga harus ada opsi python untuk melakukan operasi standar .substringBefore () yang berbasis indeks. Dan juga variasi seperti .substringBeforeLast (), dll harus ada untuk kenyamanan (kode tidak boleh diulang). Sarankan untuk memperbarui jawaban ini untuk menjelaskan mengapa indeks bekerja lebih baik dan mengapa ini harus digunakan di atas pendekatan lain termasuk yang memilih lebih tinggi sekarang dalam tanggapan fredtantini.
arntg

Jika tidak ada, indeks akan gagal.
Marc

19

Anda tidak perlu regexuntuk ini

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

Anda dapat menggunakan splitmetode ini untuk membagi string pada ':'karakter

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

Dan potong elemen [0]untuk mendapatkan bagian pertama dari string

>>> s.split(':')[0]
'Username'

9

Saya telah membandingkan berbagai teknik ini dengan Python 3.7.0 (IPython).

TLDR

  • tercepat (ketika simbol pemisah cdiketahui): regex yang telah dikompilasi sebelumnya.
  • tercepat (sebaliknya): s.partition(c)[0].
  • aman (yaitu, bila cmungkin tidak berada di s): partisi, split.
  • tidak aman: indeks, regex.

Kode

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]

Hasil

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
mengapa Anda menganggap indeks tidak aman?
Yakobus

3
s.index(c)memunculkan ValueError saat ctidak ada s. Jadi, saya menganggapnya aman ketika saya yakin bahwa string yang akan dipartisi berisi pemisah, tidak aman jika tidak.
Aristide

1
Untuk index, c ada di s, jadi tidak berbahaya dan masih tercepat.
arntg

2

Partisi () mungkin lebih baik daripada split () untuk tujuan ini karena memiliki hasil prediksi yang lebih baik untuk situasi Anda tidak memiliki pembatas atau lebih banyak pembatas.


1
Keduanya partitiondan splitakan bekerja secara transparan dengan string kosong atau tanpa pembatas. Perlu dicatat bahwa word[:word.index(':')]akan muncul dalam kedua kasus ini.
Rob Hall
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.