Anda mengacaukan sedikit memori di sini dengan semua panggilan untuk "menggantikan": kompleksitas akan menjadi n² jika Anda menghapus "o" dari "ooooooo ... o". Saya rasa ada yang bisa melakukan lebih baik, tetapi solusi ini bermanfaat karena mudah dipahami.
Zonko
1
Mengapa ini bukan loop for aktual, bukan loop for yang dikaburkan?
Shirik
Saya terbiasa menerapkan prinsip 'paling tidak mengejutkan'. Untuk loop adalah untuk penggunaan peningkatan indeks sederhana, sebagian besar waktu. Di sini, menurut saya, loop sementara lebih jelas.
yves Baumes
1
@aldo Sebagai aturan umum, lebih baik menghindari kompleksitas dan, misalnya, gunakan regex seperti yang disebutkan dalam balasan lain. Tetapi tergantung pada kebutuhan Anda, Anda mungkin ingin mengontrol dependensi proyek Anda. Cuplikan kode kecil yang melakukan apa yang sebenarnya Anda butuhkan, tidak lebih, terkadang lebih baik.
yves Baumes
158
#include<boost/algorithm/string.hpp>// include Boost, a C++ library...
std::string target("Would you like a foo of chocolate. Two foos of chocolate?");
boost::replace_all(target,"foo","bar");
Perhatikan bahwa Anda tidak harus secara eksplisit membuat std :: string untuk pola dan penggantian: boost :: replace_all (target, "foo", "bar");
Alexis Wilke
4
+1, dengan peringatan: replace_allakan segfault untuk versi peningkatan> 1.43 di Sun Studio untuk versi apa pun <12.3
Brian Vandenberg
3
boostmeningkatkan waktu kompilasi secara signifikan pada perangkat yang disematkan. Bahkan quad core ARMv7. 100 baris kode dikompilasi dalam 2 menit, tanpa peningkatan, 2 detik.
Piotr Kula
4
@ppumkin: itu berarti kompilator Anda (atau penyiapan build, atau apa pun) menyebalkan, bukan arsitektur target, yang tidak ada hubungannya dengan itu.
Daniel Kamil Kozar
Jika kompilator Anda mendukung header yang telah dikompilasi sebelumnya, sangat disarankan untuk menggunakannya saat menggunakan boost. Ini sangat menghemat waktu.
Alexey Omelchenko
33
Di C ++ 11, Anda dapat melakukan ini sebagai satu baris dengan panggilan ke regex_replace:
#include<string>#include<regex>using std::string;
string do_replace( string const& in, string const& from, string const& to ){return std::regex_replace( in, std::regex(from), to );}
string test ="Remove all spaces";
std::cout << do_replace(test," ","")<< std::endl;
Perhatikan juga bahwa itu frombisa menjadi ekspresi reguler - sehingga Anda bisa menggunakan kriteria pencocokan yang lebih canggih jika perlu. Apa yang tidak saya lihat adalah bagaimana melakukan ini tanpa menerapkan beberapa bentuk penguraian ekspresi reguler - alih-alih hanya menggunakan interpretasi langsung dari fromkarakter.
Brent Bradburn
Ini mungkin membutuhkan kompiler terbaru. Ini berfungsi dengan gcc 5.0, tetapi saya mengalami beberapa masalah dengan gcc 4.8.4.
Brent Bradburn
@nobar, ya, jika saya ingat dengan benar dukungan regex di 4.8.x tidak lengkap. Anda juga dapat melakukan pencarian yang lebih canggih, tetapi Anda mendapatkan penalti berdasarkan waktu ... Ini akan menjadi lebih lambat daripada fungsi pencarian dan penggantian yang lebih lurus ke depan.
Alexis Wilke
2
Harap dicatat bahwa ini hanya akan berfungsi untuk karakter alfanumerik yang sangat dasar dan tidak ada yang lain tanpa melakukan banyak praproses tergantung pada jenis string. Saya belum menemukan penggantian string berbasis regex tujuan umum.
Piyush Soni
17
Mengapa tidak mengembalikan string yang dimodifikasi?
Ini mengembalikan hitungan jumlah item yang diganti (untuk digunakan jika Anda ingin menjalankan ini secara berturut-turut, dll). Untuk menggunakannya:
std::string str ="one two three";int n = findAndReplace(str,"one","1");
Saya mencoba sampel ini di bawah GCC tetapi tidak dapat dikompilasi - tidak suka penggunaan T :: size_t. Mengganti T :: size_t dengan nama jenis T :: size_type memperbaiki masalah.
Andrew Wyatt
3
Cara termudah (menawarkan sesuatu yang mendekati apa yang Anda tulis) adalah dengan menggunakan Boost.Regex , khususnya regex_replace .
std :: string telah membangun metode find () dan replace (), tetapi metode ini lebih rumit untuk digunakan karena mereka memerlukan penanganan indeks dan panjang string.
Ada juga algoritma boost string, termasuk replace_all (regex mungkin agak berat untuk substitusi sederhana seperti itu).
UncleBens
3
Saya yakin ini akan berhasil. Dibutuhkan const char * sebagai parameter.
//params find and replace cannot be NULLvoidFindAndReplace( std::string& source,constchar* find,constchar* replace ){//ASSERT(find != NULL);//ASSERT(replace != NULL);size_t findLen = strlen(find);size_t replaceLen = strlen(replace);size_t pos =0;//search for the next occurrence of find within sourcewhile((pos = source.find(find, pos))!= std::string::npos){//replace the found string with the replacement
source.replace( pos, findLen, replace );//the next line keeps you from searching your replace string, //so your could replace "hello" with "hello world" //and not have it blow chunks.
pos += replaceLen;}}
Mengingat size_typeuntuk string adalah unsigned, >=pemeriksaan Anda dalam kondisi loop akan selalu true. Anda harus menggunakannya di std::string::npossana.
Pavel Minaev
size_type [jenis_ukuran] tidak tidak ditandai Itu tidak ditandatangani di banyak platform, tetapi tidak semua.
Alan
12
Mengapa di dunia ini bukan bagian dari std :: string? Apakah ada kelas String serius lainnya di dunia pemrograman yang tidak menawarkan operasi 'temukan dan ganti'? Tentunya itu lebih umum daripada memiliki dua iterator dan ingin mengganti teks di antara keduanya ?? Terkadang std :: string terasa seperti mobil dengan kaca depan spektrum yang dapat disetel tetapi tidak ada cara untuk menurunkan jendela pengemudi.
Spike0xff
@ Spike0xff boost memilikiroll_down_window
ta.speot.is
1
@ Gustafr: Kesalahan saya. Saya telah mengerjakan sistem di mana kompiler lama mendefinisikan size_t secara tidak benar.
Alan
1
// Replace all occurrences of searchStr in str with replacer// Each match is replaced only once to prevent an infinite loop// The algorithm iterates once over the input and only concatenates // to the output, so it should be reasonably efficient
std::string replace(const std::string& str,const std::string& searchStr,const std::string& replacer){// Prevent an infinite loop if the input is emptyif(searchStr ==""){return str;}
std::string result ="";size_t pos =0;size_t pos2 = str.find(searchStr, pos);while(pos2 != std::string::npos){
result += str.substr(pos, pos2-pos)+ replacer;
pos = pos2 + searchStr.length();
pos2 = str.find(searchStr, pos);}
result += str.substr(pos, str.length()-pos);return result;}
Kita hanya perlu mencari kecocokan baru dari kecocokan terakhir, itu sebabnya algoritma dengan hati-hati melacak kecocokan terakhir di pos. pos2 selalu menyimpan pertandingan berikutnya, jadi kami menggabungkan string antara pos dan pos2 ke hasil, lalu maju pos dan pos2. Jika tidak ada kecocokan lain yang dapat ditemukan, kami menggabungkan sisa string menjadi hasil.
Jawaban:
Mengapa tidak menerapkan penggantian Anda sendiri?
sumber
Berikut adalah dokumentasi resmi di replace_all.
sumber
replace_all
akan segfault untuk versi peningkatan> 1.43 di Sun Studio untuk versi apa pun <12.3boost
meningkatkan waktu kompilasi secara signifikan pada perangkat yang disematkan. Bahkan quad core ARMv7. 100 baris kode dikompilasi dalam 2 menit, tanpa peningkatan, 2 detik.Di C ++ 11, Anda dapat melakukan ini sebagai satu baris dengan panggilan ke
regex_replace
:keluaran:
sumber
from
bisa menjadi ekspresi reguler - sehingga Anda bisa menggunakan kriteria pencocokan yang lebih canggih jika perlu. Apa yang tidak saya lihat adalah bagaimana melakukan ini tanpa menerapkan beberapa bentuk penguraian ekspresi reguler - alih-alih hanya menggunakan interpretasi langsung darifrom
karakter.Mengapa tidak mengembalikan string yang dimodifikasi?
Jika Anda membutuhkan kinerja, berikut adalah fungsi yang dioptimalkan yang mengubah string input, itu tidak membuat salinan dari string:
Tes:
Keluaran:
sumber
Temukan-dan-ganti sebaris saya di tempat:
Ini mengembalikan hitungan jumlah item yang diganti (untuk digunakan jika Anda ingin menjalankan ini secara berturut-turut, dll). Untuk menggunakannya:
sumber
Cara termudah (menawarkan sesuatu yang mendekati apa yang Anda tulis) adalah dengan menggunakan Boost.Regex , khususnya regex_replace .
std :: string telah membangun metode find () dan replace (), tetapi metode ini lebih rumit untuk digunakan karena mereka memerlukan penanganan indeks dan panjang string.
sumber
Saya yakin ini akan berhasil. Dibutuhkan const char * sebagai parameter.
sumber
size_type
untuk string adalahunsigned
,>=
pemeriksaan Anda dalam kondisi loop akan selalutrue
. Anda harus menggunakannya distd::string::npos
sana.roll_down_window
sumber
Pemeriksaan untuk oldStr kosong itu penting. Jika karena alasan apa pun parameter itu kosong, Anda akan terjebak dalam loop tak terbatas.
Tapi ya gunakan solusi C ++ 11 atau Boost yang telah dicoba dan diuji jika Anda bisa.
sumber