Saya pikir apa yang ingin saya lakukan adalah tugas yang cukup umum tetapi saya tidak menemukan referensi di web. Saya memiliki teks dengan tanda baca, dan saya ingin daftar kata-kata.
"Hey, you - what are you doing here!?"
seharusnya
['hey', 'you', 'what', 'are', 'you', 'doing', 'here']
Tapi Python str.split()
hanya bekerja dengan satu argumen, jadi saya memiliki semua kata dengan tanda baca setelah saya berpisah dengan spasi putih. Ada ide?
str.split()
juga bekerja tanpa argumen sama sekaliJawaban:
Kasus di mana ekspresi reguler dibenarkan:
sumber
re
, hanya saja tidakfindall
. Jawaban di bawah memberire.split()
lebih unggul.don't
diperlakukan sebagai satu kata, daripada dipecah menjadidon
dant
.re.split ()
sumber
\w
,\W
,\s
, dan\S
. Siapa pun yang berpikir bahwa kapitalisasi bendera harus membalik maknanya harus ditembakkan melalui kepala.shift
kunci untuk melakukan kebalikan dari sesuatu.ctrl+z
batalkan vsctrl+shift+z
untuk redo. Jadishift w
, atauW
, akan menjadi kebalikan dariw
.Cara cepat lain untuk melakukan ini tanpa regexp adalah mengganti karakter terlebih dahulu, seperti di bawah ini:
sumber
Begitu banyak jawaban, namun saya tidak dapat menemukan solusi yang efisien apa yang diminta oleh judul pertanyaan (memisahkan pada beberapa pemisah yang mungkin — sebagai gantinya, banyak jawaban terpecah pada apa pun yang bukan kata, yang berbeda). Jadi di sini adalah jawaban untuk pertanyaan dalam judul, yang bergantung pada
re
modul standar dan efisien Python :dimana:
[…]
pertandingan salah satu pemisah yang terdaftar di dalam,\-
dalam ekspresi reguler di sini untuk mencegah interpretasi khusus-
sebagai indikator berbagai karakter (seperti dalamA-Z
),+
melompat satu atau lebih pembatas (itu bisa dihilangkan berkatfilter()
, tapi ini tidak perlu akan menghasilkan string kosong antara pemisah cocok), danfilter(None, …)
menghapus string kosong yang mungkin dibuat oleh pemisah leading dan trailing (karena string kosong memiliki nilai boolean palsu).Ini
re.split()
tepatnya "terbagi dengan beberapa pemisah", seperti yang diminta dalam judul pertanyaan.Solusi ini juga kebal terhadap masalah dengan karakter non-ASCII dalam kata-kata yang ditemukan dalam beberapa solusi lain (lihat komentar pertama untuk jawaban ghostdog74 ).
The
re
Modul jauh lebih efisien (dalam kecepatan dan amputasi) daripada melakukan Python loop dan tes "dengan tangan"!sumber
Cara lain, tanpa regex
sumber
"Hey, you - what are you doing here María!?"
. Solusi yang diterima tidak akan berfungsi dengan contoh sebelumnya.''.join([o if not o in string.punctuation else ' ' for o in s]).split()
o for o in s if (o in not string.punctuation or o == "'")
, tetapi kemudian menjadi terlalu rumit untuk satu-liner jika kita menambahkan patch cedbeu juga."First Name,Last Name,Street Address,City,State,Zip Code"
dan kita ingin membaginya hanya dengan koma,
. Output yang diinginkan adalah:['First Name', 'Last Name', 'Street Address', 'City', 'State', 'Zip Code']
Apa yang kita dapatkan sebagai gantinya:['First', 'Name', 'Last', 'Name', 'Street', 'Address', 'City', 'State', 'Zip', 'Code']
re
modul ini standar dan memberikan keterbacaan dan kecepatan, saya tidak mengerti mengapa itu harus dihindari.Pro-Tip: Gunakan
string.translate
untuk operasi string tercepat yang dimiliki Python.Beberapa bukti ...
Pertama, cara lambat (maaf pprzemek):
Selanjutnya, kami menggunakan
re.findall()
(seperti yang diberikan oleh jawaban yang disarankan). Lebih cepat:Akhirnya, kami menggunakan
translate
:Penjelasan:
string.translate
diimplementasikan dalam C dan tidak seperti banyak fungsi manipulasi string di Python,string.translate
tidak menghasilkan string baru. Jadi ini tentang secepat Anda bisa mendapatkan untuk penggantian string.Ini agak canggung, karena membutuhkan tabel terjemahan untuk melakukan keajaiban ini. Anda dapat membuat tabel terjemahan dengan
maketrans()
fungsi kenyamanan. Tujuannya di sini adalah untuk menerjemahkan semua karakter yang tidak diinginkan ke spasi. Pengganti satu-satu. Sekali lagi, tidak ada data baru yang dihasilkan. Jadi ini cepat !Selanjutnya, kami menggunakan tua yang baik
split()
.split()
secara default akan beroperasi pada semua karakter spasi, mengelompokkannya untuk pemisahan. Hasilnya akan menjadi daftar kata yang Anda inginkan. Dan pendekatan ini hampir 4x lebih cepat darire.findall()
!sumber
patt = re.compile(ur'\w+', re.UNICODE); patt.findall(S)
lebih cepat daripada menerjemahkan, karena Anda harus menyandikan string sebelum menerapkan transformasi, dan mendekode setiap item dalam daftar setelah pemisahan untuk kembali ke unicode.s.translate(''.join([(chr(i) if chr(i) not in seps else seps[0]) for i in range(256)])).split(seps[0])
Saya memiliki dilema yang sama dan tidak ingin menggunakan modul 're'.
sumber
re
modul, yang lebih cepat dan lebih jelas (bukan berarti ekspresi reguler sangat jelas, tetapi karena cara ini lebih pendek dan langsung)?Pertama, saya ingin setuju dengan orang lain bahwa regex atau
str.translate(...)
solusi berbasis paling performan. Untuk kasus penggunaan saya, kinerja fungsi ini tidak signifikan, jadi saya ingin menambahkan ide yang saya pertimbangkan dengan kriteria itu.Tujuan utama saya adalah untuk menggeneralisasi ide dari beberapa jawaban lain menjadi satu solusi yang dapat bekerja untuk string yang berisi lebih dari sekedar kata regex (yaitu, daftar hitam subset eksplisit karakter tanda baca vs karakter kata daftar putih).
Perhatikan bahwa, dalam pendekatan apa pun, orang mungkin juga mempertimbangkan untuk menggunakan
string.punctuation
menggantikan daftar yang ditentukan secara manual.Opsi 1 - re.sub
Saya terkejut melihat tidak ada jawaban sejauh ini menggunakan re.sub (...) . Saya menemukan ini pendekatan yang sederhana dan alami untuk masalah ini.
Dalam solusi ini, saya menyarangkan panggilan ke
re.sub(...)
dalamre.split(...)
- tetapi jika kinerja sangat penting, mengkompilasi regex di luar bisa bermanfaat - untuk kasus penggunaan saya, perbedaannya tidak signifikan, jadi saya lebih suka kesederhanaan dan keterbacaan.Opsi 2 - str.replace
Ini adalah beberapa baris lagi, tetapi memiliki keuntungan diperluas tanpa harus memeriksa apakah Anda perlu melarikan diri dari karakter tertentu di regex.
Akan lebih baik untuk dapat memetakan str.replace ke string sebagai gantinya, tapi saya tidak berpikir itu bisa dilakukan dengan string yang tidak dapat diubah, dan sementara memetakan terhadap daftar karakter akan bekerja, menjalankan setiap penggantian terhadap setiap karakter terdengar berlebihan. (Edit: Lihat opsi selanjutnya untuk contoh fungsional.)
Opsi 3 - functools.reduce
(Dalam Python 2,
reduce
tersedia di namespace global tanpa mengimpornya dari functools.)sumber
str.translate
- itu bukan unicode-mampu tetapi kemungkinan besar lebih cepat daripada metode lain dan karena itu mungkin baik dalam beberapa kasus:replacements=',-!?'; import string; my_str = my_str.translate(string.maketrans(replacements, ' ' * len(replacements)))
Juga di sini adalah wajib untuk memiliki penggantian sebagai rangkaian karakter, bukan tuple atau daftar.Maka ini menjadi tiga baris:
Penjelasan
Inilah yang di Haskell dikenal sebagai List monad. Gagasan di balik monad adalah bahwa sekali "di monad" Anda "tetap di monad" sampai sesuatu membawa Anda keluar. Misalnya di Haskell, katakan Anda memetakan
range(n) -> [1,2,...,n]
fungsi python di atas Daftar. Jika hasilnya Daftar, itu akan ditambahkan ke Daftar di tempat, sehingga Anda akan mendapatkan sesuatu sepertimap(range, [3,4,1]) -> [0,1,2,0,1,2,3,0]
. Ini dikenal sebagai peta-append (atau mappend, atau mungkin sesuatu seperti itu). Idenya di sini adalah bahwa Anda memiliki operasi ini yang Anda terapkan (membagi pada token), dan setiap kali Anda melakukannya, Anda bergabung hasilnya ke dalam daftar.Anda dapat mengabstraksi ini menjadi fungsi dan
tokens=string.punctuation
secara default.Keuntungan dari pendekatan ini:
sumber
map_then_append
dapat digunakan untuk membuat masalah menjadi 2-liner, serta banyak masalah lain yang lebih mudah ditulis. Sebagian besar solusi lain menggunakanre
modul ekspresi reguler , yang bukan python. Tapi saya tidak senang dengan bagaimana saya membuat jawaban saya tampak tidak menarik dan menggembung ketika itu benar-benar singkat ... Saya akan mengeditnya ...fragments
hasil saya hanyalah daftar karakter dalam string (termasuk token).fragments = ['the,string']
,fragments = 'the,string'
ataufragments = list('the,string')
dan tidak satupun dari mereka yang menghasilkan output yang benar.coba ini:
ini akan dicetak
['Hey', 'you', 'what', 'are', 'you', 'doing', 'here']
sumber
Gunakan ganti dua kali:
menghasilkan:
sumber
Saya suka re , tapi ini solusi saya tanpanya:
September .__ berisi__ adalah metode yang digunakan oleh operator 'in'. Pada dasarnya sama dengan
tetapi lebih nyaman di sini.
groupby mendapatkan string dan fungsi kami. Ini membagi string dalam kelompok menggunakan fungsi itu: setiap kali nilai fungsi berubah - grup baru dihasilkan. Jadi, September .__ berisi__ persis apa yang kita butuhkan.
groupby mengembalikan urutan pasangan, di mana pasangan [0] adalah hasil dari fungsi kami dan pasangan [1] adalah grup. Menggunakan 'jika bukan k' kami memfilter grup dengan pemisah (karena hasil September .__ berisi__ adalah True on separator). Yah, itu saja - sekarang kita memiliki urutan grup di mana masing-masing adalah kata (grup sebenarnya adalah iterable jadi kami menggunakan gabungan untuk mengubahnya menjadi string).
Solusi ini cukup umum, karena menggunakan fungsi untuk memisahkan string (Anda dapat membaginya dengan kondisi apa pun yang Anda butuhkan). Juga, itu tidak membuat string / daftar menengah (Anda dapat menghapus bergabung dan ekspresi akan menjadi malas, karena setiap grup adalah iterator)
sumber
Alih-alih menggunakan fungsi modul re.split Anda dapat mencapai hasil yang sama dengan menggunakan metode panda series.str.split.
Pertama, buat seri dengan string di atas dan kemudian terapkan metode ke seri.
thestring = pd.Series("Hey, you - what are you doing here!?") thestring.str.split(pat = ',|-')
pat parameter mengambil pembatas dan mengembalikan string split sebagai array. Di sini dua pembatas dilewatkan menggunakan | (atau operator). Outputnya adalah sebagai berikut:
[Hey, you , what are you doing here!?]
sumber
Saya kembali berkenalan dengan Python dan membutuhkan hal yang sama. Solusi findall mungkin lebih baik, tetapi saya datang dengan ini:
sumber
menggunakan maketrans dan terjemahkan Anda dapat melakukannya dengan mudah dan rapi
sumber
Di Python 3, Anda bisa menggunakan metode dari PY4E - Python untuk Semua Orang .
your_string.translate(your_string.maketrans(fromstr, tostr, deletestr))
Anda dapat melihat "tanda baca":
Sebagai contoh Anda:
Untuk informasi lebih lanjut, Anda dapat merujuk:
sumber
Cara lain untuk mencapai ini adalah dengan menggunakan Natural Language Tool Kit ( nltk ).
Ini mencetak:
['Hey', 'you', 'what', 'are', 'you', 'doing', 'here']
Kelemahan terbesar dari metode ini adalah Anda harus menginstal paket nltk .
Keuntungannya adalah Anda dapat melakukan banyak hal menyenangkan dengan sisa paket nltk begitu Anda mendapatkan token Anda.
sumber
Pertama-tama, saya tidak berpikir bahwa maksud Anda adalah untuk benar-benar menggunakan tanda baca sebagai pembatas dalam fungsi split. Deskripsi Anda menunjukkan bahwa Anda hanya ingin menghilangkan tanda baca dari string yang dihasilkan.
Saya menemukan ini cukup sering, dan solusi yang biasa saya tidak perlu kembali.
Fungsi lambda satu-lapis dengan pemahaman daftar:
(membutuhkan
import string
):Fungsi (tradisional)
Sebagai fungsi tradisional, ini masih hanya dua baris dengan pemahaman daftar (selain
import string
):Ini juga akan secara alami membuat kontraksi dan kata-kata yang ditulis dengan tanda penghubung utuh. Anda selalu dapat menggunakan
text.replace("-", " ")
untuk mengubah tanda hubung menjadi spasi sebelum pemisahan.Fungsi Umum tanpa Lambda atau Daftar Pemahaman
Untuk solusi yang lebih umum (di mana Anda dapat menentukan karakter untuk dihilangkan), dan tanpa pemahaman daftar, Anda mendapatkan:
Tentu saja, Anda selalu dapat menggeneralisasi fungsi lambda ke string karakter tertentu juga.
sumber
Pertama-tama, selalu gunakan re.compile () sebelum melakukan operasi RegEx dalam satu lingkaran karena ia bekerja lebih cepat daripada operasi normal.
jadi untuk masalah Anda pertama-tama kompilasi pola dan kemudian lakukan tindakan padanya.
sumber
Inilah jawabannya dengan beberapa penjelasan.
atau dalam satu baris, kita bisa melakukan ini:
jawaban yang diperbarui
sumber
Buat fungsi yang mengambil sebagai input dua string (string sumber untuk dipisah dan string pembatas pemisah) dan mengeluarkan daftar kata-kata split:
sumber
Saya suka solusi pprzemek karena tidak berasumsi bahwa pembatas adalah karakter tunggal dan tidak mencoba memanfaatkan regex (yang tidak akan bekerja dengan baik jika jumlah pemisah menjadi gila lama).
Berikut ini versi yang lebih mudah dibaca dari solusi di atas untuk kejelasan:
sumber
mendapat masalah yang sama dengan @ooboo dan menemukan topik ini @ ghostdog74 menginspirasi saya, mungkin seseorang menemukan solusi saya berguna
masukan sesuatu di tempat spasi dan pisah menggunakan karakter yang sama jika Anda tidak ingin membagi di spasi.
sumber
Ini adalah perjalanan saya dengan beberapa pembatas:
sumber
Saya pikir berikut ini adalah jawaban terbaik untuk menyesuaikan kebutuhan Anda:
\W+
mungkin cocok untuk kasus ini, tetapi mungkin tidak cocok untuk kasus lain.sumber
\w
dan\W
solusi bukanlah jawaban untuk (judul) pertanyaan. Perhatikan bahwa dalam jawaban Anda,|
harus dihapus (yang Anda pikirkanexpr0|expr1
bukan[char0 char1…]
). Lebih jauh lagi, tidak perlucompile()
ekspresi reguler.Inilah saya mengambilnya ....
sumber
Saya suka
replace()
cara yang terbaik. Prosedur berikut mengubah semua pemisah yang didefinisikan dalam stringsplitlist
menjadi pemisah pertama displitlist
kemudian memisahkan teks pada satu pemisah itu. Itu juga menjelaskan jikasplitlist
kebetulan adalah string kosong. Ini mengembalikan daftar kata-kata, tanpa string kosong di dalamnya.sumber
Ini adalah penggunaannya:
sumber
Jika Anda ingin operasi yang dapat dibalik (mempertahankan pembatas), Anda dapat menggunakan fungsi ini:
sumber
Saya baru-baru ini perlu melakukan ini tetapi menginginkan fungsi yang agak cocok dengan
str.split
fungsi perpustakaan standar , fungsi ini berperilaku sama dengan perpustakaan standar ketika dipanggil dengan argumen 0 atau 1.CATATAN : Fungsi ini hanya berguna ketika pemisah Anda terdiri dari satu karakter (seperti yang digunakan pengguna saya).
sumber