Saya mencoba untuk mengulangi kata-kata string.
String dapat dianggap terdiri dari kata-kata yang dipisahkan oleh spasi.
Perhatikan bahwa saya tidak tertarik pada fungsi string C atau jenis manipulasi / akses semacam itu. Selain itu, mohon didahulukan keanggunan daripada efisiensi dalam jawaban Anda.
Solusi terbaik yang saya miliki saat ini adalah:
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main()
{
string s = "Somewhere down the road";
istringstream iss(s);
do
{
string subs;
iss >> subs;
cout << "Substring: " << subs << endl;
} while (iss);
}
Apakah ada cara yang lebih elegan untuk melakukan ini?
while (iss) { string subs; iss >> subs; cout << "Substring: " << sub << endl; }
string sub; while (iss >> sub) cout << "Substring: " << sub << '\n';
Jawaban:
Untuk apa nilainya, inilah cara lain untuk mengekstrak token dari string input, hanya mengandalkan fasilitas perpustakaan standar. Ini adalah contoh kekuatan dan keanggunan di balik desain STL.
Alih-alih menyalin token yang diekstraksi ke aliran output, orang bisa memasukkannya ke dalam wadah, menggunakan
copy
algoritma generik yang sama .... atau buat
vector
langsung:sumber
Saya menggunakan ini untuk membagi string dengan pembatas. Yang pertama menempatkan hasilnya dalam vektor pra-dibangun, yang kedua mengembalikan vektor baru.
Perhatikan bahwa solusi ini tidak melewati token kosong, jadi yang berikut ini akan menemukan 4 item, salah satunya kosong:
sumber
empty()
pemeriksaan:if (!item.empty()) elems.push_back(item)
->
?f(split(s, d, v))
sambil tetap mendapat manfaat dari pra-alokasivector
jika Anda suka.Solusi yang mungkin menggunakan Boost mungkin:
Pendekatan ini mungkin bahkan lebih cepat daripada
stringstream
pendekatan itu. Dan karena ini adalah fungsi templat generik, ia dapat digunakan untuk membagi jenis string lainnya (wchar, dll. Atau UTF-8) menggunakan semua jenis pembatas.Lihat dokumentasi untuk detailnya.
sumber
sumber
getline
dalamwhile
kondisi misalnya untuk membelah dengan koma, gunakanwhile(getline(ss, buff, ','))
.Bagi mereka yang tidak duduk dengan baik untuk mengorbankan semua efisiensi untuk ukuran kode dan melihat "efisien" sebagai jenis keanggunan, berikut ini akan menyentuh sweet spot (dan saya pikir kelas templat templat adalah tambahan yang luar biasa elegan.):
Saya biasanya memilih untuk menggunakan
std::vector<std::string>
tipe sebagai parameter kedua saya (ContainerT
) ... tetapilist<>
jauh lebih cepat daripadavector<>
ketika akses langsung tidak diperlukan, dan Anda bahkan dapat membuat kelas string Anda sendiri dan menggunakan sesuatu seperti distd::list<subString>
manasubString
tidak melakukan salinan untuk kecepatan luar biasa meningkat.Ini lebih dari dua kali lipat tokenize tercepat di halaman ini dan hampir 5 kali lebih cepat daripada yang lain. Juga dengan tipe parameter sempurna Anda dapat menghilangkan semua string dan menyalin daftar untuk peningkatan kecepatan tambahan.
Selain itu itu tidak melakukan pengembalian hasil (sangat tidak efisien), melainkan melewati token sebagai referensi, sehingga juga memungkinkan Anda untuk membangun token menggunakan beberapa panggilan jika Anda menginginkannya.
Terakhir memungkinkan Anda menentukan apakah akan memangkas token kosong dari hasil melalui parameter opsional terakhir.
Yang dibutuhkan hanyalah
std::string
... sisanya opsional. Itu tidak menggunakan aliran atau meningkatkan perpustakaan, tetapi cukup fleksibel untuk dapat menerima beberapa tipe asing ini secara alami.sumber
typedef ContainerT Base; typedef typename Base::value_type ValueType; typedef typename ValueType::size_type SizeType;
Kemudian untuk mengganti value_type dan size_types sesuai.trimEmpty = true
. Ingatlah bahwa"abo"
ini bukan pembatas dalam jawaban ini, tetapi daftar karakter pembatas. Akan mudah untuk memodifikasinya untuk mengambil serangkaian karakter pembatas tunggal (saya pikirstr.find_first_of
harus berubah menjadistr.find_first
, tapi saya bisa salah ... tidak dapat menguji)Ini solusi lain. Ini kompak dan cukup efisien:
Ini dapat dengan mudah templatised untuk menangani pemisah string, string lebar, dll.
Perhatikan bahwa pemisahan
""
menghasilkan string tunggal kosong dan pemisahan","
(mis. Sep) menghasilkan dua string kosong.Itu juga dapat dengan mudah diperluas untuk melewati token kosong:
Jika memisahkan string pada beberapa pembatas saat melewatkan token kosong diinginkan, versi ini dapat digunakan:
sumber
Ini adalah cara favorit saya untuk beralih melalui string. Anda dapat melakukan apa pun yang Anda inginkan per kata.
sumber
word
sebagaichar
?stringstream ss("Hello World, this is*@#&$(@ a string"); char c; while(ss >> c) cout << c;
Ini mirip dengan pertanyaan Stack Overflow Bagaimana cara tokenize sebuah string dalam C ++? .
sumber
Saya suka yang berikut ini karena menempatkan hasilnya ke dalam vektor, mendukung string sebagai delim dan memberikan kontrol untuk menjaga nilai kosong. Tapi, itu tidak terlihat sebagus itu.
Tentu saja, Boost memiliki
split()
yang berfungsi sebagian seperti itu. Dan, jika dengan 'ruang putih', Anda benar-benar berarti semua jenis ruang putih, menggunakan split Boost denganis_any_of()
karya-karya hebat.sumber
STL belum memiliki metode seperti itu.
Namun, Anda bisa menggunakan
strtok()
fungsi C dengan menggunakanstd::string::c_str()
anggota, atau Anda dapat menulis sendiri. Berikut adalah contoh kode yang saya temukan setelah pencarian cepat Google ( "STL string split" ):Diambil dari: http://oopweb.com/CPP/Documents/CPPHOWTO/Volume/C++Programming-HOWTO-7.html
Jika Anda memiliki pertanyaan tentang contoh kode, tinggalkan komentar dan saya akan menjelaskan.
Dan hanya karena itu tidak menerapkan
typedef
iterator yang disebut atau kelebihan<<
operator tidak berarti itu adalah kode yang buruk. Saya menggunakan fungsi C cukup sering. Misalnya,printf
danscanf
keduanya lebih cepat daripadastd::cin
danstd::cout
(secara signifikan),fopen
sintaksisnya jauh lebih ramah untuk tipe biner, dan mereka juga cenderung menghasilkan EXE yang lebih kecil.Jangan dijual berdasarkan kesepakatan "Keanggunan atas kinerja" ini .
sumber
Berikut adalah fungsi split yang:
mengabaikan token kosong (dapat dengan mudah diubah)
Contoh penggunaan:
sumber
Saya punya solusi 2 baris untuk masalah ini:
Maka alih-alih mencetak Anda bisa memasukkannya ke dalam vektor.
sumber
Namun cara lain yang fleksibel dan cepat
Untuk menggunakannya dengan vektor string (Edit: Karena seseorang menunjukkan tidak mewarisi kelas STL ... hrmf;)):
Itu dia! Dan itu hanya satu cara untuk menggunakan tokenizer, seperti cara menghitung kata:
Terbatas oleh imajinasi;)
sumber
Appender
catatan "Mengapa kita tidak mewarisi kelas dari kelas STL?"Berikut adalah solusi sederhana yang hanya menggunakan pustaka regex standar
Argumen regex memungkinkan memeriksa beberapa argumen (spasi, koma, dll.)
Saya biasanya hanya memeriksa untuk membagi spasi dan koma, jadi saya juga memiliki fungsi default ini:
The
"[\\s,]+"
memeriksa ruang (\\s
) dan koma (,
).Catatan, jika Anda ingin membagi
wstring
bukanstring
,std::regex
menjadistd::wregex
sregex_token_iterator
menjadiwsregex_token_iterator
Catatan, Anda mungkin juga ingin mengambil argumen string dengan referensi, tergantung pada kompiler Anda.
sumber
R"([\s,]+)"
.Menggunakan
std::stringstream
seperti yang Anda miliki berfungsi dengan sangat baik, dan melakukan apa yang Anda inginkan. Jika Anda hanya mencari cara berbeda dalam melakukan sesuatu, Anda dapat menggunakanstd::find()
/std::find_first_of()
danstd::string::substr()
.Ini sebuah contoh:
sumber
prev_pos = pos += delimiter.length();
Jika Anda ingin menggunakan boost, tetapi ingin menggunakan seluruh string sebagai pembatas (alih-alih karakter tunggal seperti dalam sebagian besar solusi yang diusulkan sebelumnya), Anda dapat menggunakan
boost_split_iterator
.Kode contoh termasuk template yang mudah digunakan:
sumber
Inilah solusi regex yang hanya menggunakan pustaka regex standar. (Saya agak berkarat, jadi mungkin ada beberapa kesalahan sintaksis, tapi ini setidaknya merupakan ide umum)
sumber
Ada fungsi bernama
strtok
.sumber
strtok
berasal dari pustaka standar C, bukan C ++. Tidak aman untuk digunakan dalam program multithreaded. Ini memodifikasi string input.strtok
saat utas lain masih memproses, pointer char ini akan ditimpa, dan kedua utas tersebut akan memiliki hasil yang salah. mkssoftware.com/docs/man3/strtok.3.aspThe stringstream dapat nyaman jika Anda perlu untuk mengurai string dengan simbol non-space:
sumber
Sejauh ini saya menggunakan yang ada di Boost , tapi saya butuh sesuatu yang tidak bergantung padanya, jadi saya sampai pada ini:
Poin yang bagus adalah
separators
Anda dapat melewati lebih dari satu karakter.sumber
Saya telah menggulung saya sendiri menggunakan strtok dan menggunakan dorongan untuk membagi string. Metode terbaik yang saya temukan adalah C + + String Toolkit Library . Ini sangat fleksibel dan cepat.
Toolkit ini memiliki lebih banyak fleksibilitas daripada yang ditunjukkan contoh sederhana ini tetapi kegunaannya dalam mengurai string menjadi elemen yang berguna sangat luar biasa.
sumber
Pendek dan elegan
dapat menggunakan string apa pun sebagai pembatas, juga dapat digunakan dengan data biner (std :: string mendukung data biner, termasuk nol)
menggunakan:
keluaran:
sumber
Saya membuat ini karena saya membutuhkan cara mudah untuk memisahkan string dan string berbasis-c ... Semoga orang lain dapat menemukannya berguna juga. Juga tidak bergantung pada token dan Anda dapat menggunakan bidang sebagai pembatas, yang merupakan kunci lain yang saya butuhkan.
Saya yakin ada perbaikan yang dapat dilakukan untuk lebih meningkatkan keanggunannya dan silakan lakukan dengan segala cara
StringSplitter.hpp:
StringSplitter.cpp:
Contoh:
Akan menghasilkan:
Ini
adalah
sebuah
contoh
cstring
Untuk menyimpan entri kosong (secara default akan dikosongkan):
Tujuannya adalah membuatnya mirip dengan metode C # 's Split () di mana pemisahan string semudah:
Saya harap orang lain dapat menemukan ini sama bermanfaatnya dengan saya.
sumber
Bagaimana dengan ini:
sumber
Jawaban ini mengambil string dan memasukkannya ke dalam vektor string. Ini menggunakan perpustakaan boost.
sumber
Inilah cara lain untuk melakukannya ..
sumber
Saya suka menggunakan metode boost / regex untuk tugas ini karena mereka memberikan fleksibilitas maksimum untuk menentukan kriteria pemisahan.
sumber
Baru-baru ini saya harus membagi kata yang berhias unta menjadi subword. Tidak ada pembatas, hanya karakter atas.
Misalnya, ini membagi "AQueryTrades" menjadi "A", "Query" dan "Trades". Fungsi ini bekerja dengan string sempit dan lebar. Karena itu menghormati lokal saat ini ia membagi "RaumfahrtÜberwachungsVerordnung" menjadi "Raumfahrt", "Überwachungs" dan "Verordnung".
Catatan
std::upper
harus benar-benar diteruskan sebagai argumen templat fungsi. Maka yang lebih umum dari fungsi ini dapat dibagi pada pembatas seperti","
,";"
atau" "
juga.sumber
std::isupper
bisa dilewatkan sebagai argumen, bukanstd::upper
. Kedua, letakkantypename
sebelumString::const_iterator
.sumber
Menggunakan
std::string_view
danrange-v3
perpustakaan Eric Niebler :https://wandbox.org/permlink/kW5lwRCL1pxjp2pW
Dengan menggunakan rentang
for
loop alih-alihranges::for_each
algoritma:sumber