Saya memiliki string seperti ini:
this is "a test"
Saya mencoba menulis sesuatu dengan Python untuk membaginya dengan spasi sambil mengabaikan spasi dalam tanda kutip. Hasil yang saya cari adalah:
['this','is','a test']
PS. Saya tahu Anda akan bertanya "apa yang terjadi jika ada tanda kutip di dalam tanda kutip, yah, dalam aplikasi saya, itu tidak akan pernah terjadi.
Jawaban:
Anda ingin
split
, darishlex
modul bawaan.Ini harus melakukan apa yang Anda inginkan.
sumber
shlex.split('this is "a test"', posix=False)
kembali['this', 'is', '"a test"']
shlex.split()
akan memicuUnicodeEncodeError
pengecualian.Lihatlah
shlex
modul, khususnyashlex.split
.sumber
Saya melihat pendekatan regex di sini yang terlihat rumit dan / atau salah. Ini mengejutkan saya, karena sintaksis regex dapat dengan mudah menggambarkan "ruang kosong atau hal-dikelilingi-oleh-kutipan", dan kebanyakan mesin regex (termasuk Python) dapat dibagi pada sebuah regex. Jadi jika Anda akan menggunakan regex, mengapa tidak mengatakan dengan tepat apa yang Anda maksud ?:
Penjelasan:
shlex mungkin menyediakan lebih banyak fitur.
sumber
Tergantung pada kasus penggunaan Anda, Anda mungkin juga ingin memeriksa
csv
modul:Keluaran:
sumber
""
) untuk mewakili satu tanda kutip ganda"
, sehingga akan mengubah dua tanda kutip ganda menjadi tanda kutip tunggal'this is "a string""'
dan'this is "a string"""'
keduanya akan dipetakan ke['this', 'is', 'a string"']
Saya menggunakan shlex.split untuk memproses 70.000.000 baris squid log, ini sangat lambat. Jadi saya beralih ke kembali.
Silakan coba ini, jika Anda memiliki masalah kinerja dengan shlex.
sumber
Karena pertanyaan ini ditandai dengan regex, saya memutuskan untuk mencoba pendekatan regex. Saya pertama-tama mengganti semua spasi di bagian kutipan dengan \ x00, lalu pisah dengan spasi, lalu ganti \ x00 kembali ke spasi di setiap bagian.
Kedua versi melakukan hal yang sama, tetapi splitter sedikit lebih mudah dibaca daripada splitter2.
sumber
Tampaknya karena alasan kinerja
re
lebih cepat. Inilah solusi saya menggunakan operator serakah yang menjaga kutipan luar:Hasil:
Ini meninggalkan konstruksi seperti
aaa"bla blub"bbb
bersama karena token ini tidak dipisahkan oleh spasi. Jika string berisi karakter yang lolos, Anda dapat mencocokkan seperti itu:Harap dicatat bahwa ini juga cocok dengan string kosong
""
melalui\S
bagian dari pola.sumber
,
via'(?:".*?"|[^,])+'
). Hal yang sama berlaku untuk karakter kutipan (terlampir).Masalah utama dengan
shlex
pendekatan yang diterima adalah bahwa ia tidak mengabaikan karakter melarikan diri di luar substring yang dikutip, dan memberikan hasil yang sedikit tak terduga dalam beberapa kasus sudut.Saya memiliki use case berikut, di mana saya membutuhkan fungsi split yang membagi string input sedemikian rupa sehingga baik substring yang dikutip tunggal atau ganda dikutip dipertahankan, dengan kemampuan untuk keluar dari kutipan dalam substring tersebut. Kutipan dalam string yang tidak dikutip tidak boleh diperlakukan secara berbeda dari karakter lain. Beberapa contoh uji kasus dengan output yang diharapkan:
Saya berakhir dengan fungsi berikut untuk membagi string sehingga hasil output yang diharapkan untuk semua string input:
Aplikasi pengujian berikut memeriksa hasil pendekatan lain (
shlex
dancsv
untuk saat ini) dan implementasi pemisahan kustom:Keluaran:
Jadi kinerja jauh lebih baik daripada
shlex
, dan dapat ditingkatkan lebih lanjut dengan mengkompilasi ekspresi reguler, dalam hal ini akan mengunggulicsv
pendekatan.sumber
shlex
tidak berperilaku seperti yang diharapkan untuk kasus penggunaan saya.Untuk menyimpan kutipan, gunakan fungsi ini:
sumber
Tes kecepatan untuk jawaban yang berbeda:
sumber
Hmm, sepertinya tidak bisa menemukan tombol "Balas" ... lagi pula, jawaban ini didasarkan pada pendekatan oleh Kate, tetapi dengan benar membagi string dengan substring yang berisi tanda kutip yang lolos dan juga menghilangkan tanda kutip mulai dan akhir dari substring:
Ini berfungsi pada string seperti
'This is " a \\\"test\\\"\\\'s substring"'
(sayangnya, markup gila diperlukan untuk menjaga Python dari menghapus lolos).Jika hasil yang keluar dalam string dalam daftar yang dikembalikan tidak diinginkan, Anda dapat menggunakan versi fungsi yang sedikit diubah ini:
sumber
Untuk mengatasi masalah unicode di beberapa versi Python 2, saya sarankan:
sumber
split = lambda a: [b.decode('utf-8') for b in _split(a)]
jika tidak, Anda akan mendapatkan:UnicodeDecodeError: 'ascii' codec can't decode byte ... in position ...: ordinal not in range(128)
Sebagai opsi coba tssplit:
sumber
Saya menyarankan:
string uji:
untuk menangkap juga "" dan '':
hasil:
untuk mengabaikan "" dan '' kosong:
hasil:
sumber
re.findall("(?:\".*?\"|'.*?'|[^\s'\"]+)", s)
.Jika Anda tidak peduli tentang sub string daripada yang sederhana
Kinerja:
Atau modul string
Kinerja: Modul string tampaknya berkinerja lebih baik daripada metode string
Atau Anda bisa menggunakan mesin RE
Performa
Untuk string yang sangat panjang Anda tidak harus memuat seluruh string ke dalam memori dan sebaliknya membagi garis atau menggunakan loop berulang
sumber
Coba ini:
Beberapa string uji:
sumber
adamsplit("This is 'a test'")
→['This', 'is', "'a", "test'"]