C ++ 'da bir dizenin bir kısmını başka bir dizeyle değiştirmek mümkün mü?
Temel olarak, bunu yapmak istiyorum:
QString string("hello $name");
string.replace("$name", "Somename");
Ancak Standard C ++ kütüphanelerini kullanmak istiyorum.
C ++ 'da bir dizenin bir kısmını başka bir dizeyle değiştirmek mümkün mü?
Temel olarak, bunu yapmak istiyorum:
QString string("hello $name");
string.replace("$name", "Somename");
Ancak Standard C ++ kütüphanelerini kullanmak istiyorum.
Yanıtlar:
Bir dize ( find
) içinde bir alt dize bulma işlevi ve bir dizedeki belirli bir aralığı başka bir dize ( replace
) ile değiştirme işlevi vardır , böylece istediğiniz efekti elde etmek için bunları birleştirebilirsiniz:
bool replace(std::string& str, const std::string& from, const std::string& to) {
size_t start_pos = str.find(from);
if(start_pos == std::string::npos)
return false;
str.replace(start_pos, from.length(), to);
return true;
}
std::string string("hello $name");
replace(string, "$name", "Somename");
Bir yoruma yanıt olarak, replaceAll
muhtemelen şöyle bir şey olacağını düşünüyorum :
void replaceAll(std::string& str, const std::string& from, const std::string& to) {
if(from.empty())
return;
size_t start_pos = 0;
while((start_pos = str.find(from, start_pos)) != std::string::npos) {
str.replace(start_pos, from.length(), to);
start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
}
}
from
ve to
başına geçti const
referans? Orada yoksa işleviniz ne yapar from
? -1
Bunun için benden.
const
ve böyle bir yardımcı yöntem yazsaydım, yalnızca değiştirme geçerli
const
, C ++ 'ın en iyi araçlarından birini göz ardı etmektir. Referans başına const
geçiş, işlev parametreleri için varsayılan mod olmalıdır. (FTR, olmadan, const
işlevinize dizgi değişmezlerini bile geçiremezsiniz, çünkü geçici olmayanları const
referans olmayanlara bağlayamazsınız . Bu nedenle işlev, yazıldığını bile yapmaz.)
C ++ 11 ile şöyle kullanabilirsiniz std::regex
:
#include <regex>
...
std::string string("hello $name");
string = std::regex_replace(string, std::regex("\\$name"), "Somename");
Bir kaçış karakterinden kaçmak için çift ters eğik çizgi gereklidir.
std::regex_replace
Qt dizesini kabul etmiyor.
string
ile string.toStdString()
.
String
için std::string
soru Qt ile ilgili değil, çünkü. Lütfen bunu yapmayı düşünün - Daha sonra cevabınızı memnuniyetle onaylayacağım.
R"(\$name)"
yerine yazmaya izin verir "\\$name"
.
std::string
bir replace
yöntemi var, aradığınız şey bu mu?
Deneyebilirsiniz:
s.replace(s.find("$name"), sizeof("$name") - 1, "Somename");
Kendimi denemedim, sadece find()
ve üzerindeki belgeleri okuyun replace()
.
Yeni dizenin döndürülmesi için şunu kullanın:
std::string ReplaceString(std::string subject, const std::string& search,
const std::string& replace) {
size_t pos = 0;
while ((pos = subject.find(search, pos)) != std::string::npos) {
subject.replace(pos, search.length(), replace);
pos += replace.length();
}
return subject;
}
Performansa ihtiyacınız varsa, burada giriş dizesini değiştiren optimize edilmiş bir işlev vardır, dizenin bir kopyasını oluşturmaz:
void ReplaceStringInPlace(std::string& subject, const std::string& search,
const std::string& replace) {
size_t pos = 0;
while ((pos = subject.find(search, pos)) != std::string::npos) {
subject.replace(pos, search.length(), replace);
pos += replace.length();
}
}
Testler:
std::string input = "abc abc def";
std::cout << "Input string: " << input << std::endl;
std::cout << "ReplaceString() return value: "
<< ReplaceString(input, "bc", "!!") << std::endl;
std::cout << "ReplaceString() input string not modified: "
<< input << std::endl;
ReplaceStringInPlace(input, "bc", "??");
std::cout << "ReplaceStringInPlace() input string modified: "
<< input << std::endl;
Çıktı:
Input string: abc abc def
ReplaceString() return value: a!! a!! def
ReplaceString() input string not modified: abc abc def
ReplaceStringInPlace() input string modified: a?? a?? def
Evet, bunu yapabilirsiniz, ancak ilk dizenin string'in find () üyesiyle konumunu bulmalı ve yerine replace () üyesiyle değiştirmelisiniz.
string s("hello $name");
size_type pos = s.find( "$name" );
if ( pos != string::npos ) {
s.replace( pos, 5, "somename" ); // 5 = length( $name )
}
Standart Kütüphaneyi kullanmayı planlıyorsanız, tüm bunları çok iyi kapsayan C ++ Standart Kütüphanesi kitabının bir kopyasını gerçekten tutmalısınız .
Ben genellikle bu kullanın:
std::string& replace(std::string& s, const std::string& from, const std::string& to)
{
if(!from.empty())
for(size_t pos = 0; (pos = s.find(from, pos)) != std::string::npos; pos += to.size())
s.replace(pos, from.size(), to);
return s;
}
Hiçbir şey std::string::find()
bulana kadar aranan dizenin diğer oluşumlarını bulmak için tekrar tekrar çağırır std::string::find()
. Eşleşmenin konumunustd::string::find()
döndürdüğü için yineleyicileri geçersiz kılma sorunumuz yoktur.
Bu bir seçenek gibi geliyor
string.replace(string.find("%s"), string("%s").size(), "Something");
Bunu bir işlevde sarabilirsiniz, ancak bu tek satırlık çözüm kabul edilebilir geliyor. Sorun şu ki, bu sadece ilk oluşumu değiştirecek, üzerinde döngü yapmak isteyebilirsiniz, ancak aynı dizeye ( %s
) aynı token ( ) ile birkaç değişken eklemenize izin verir
str.replace(str.find("%s"), string("%s").size(), "Something");
Tüm dizeler std :: string ise, sizeof()
C ++ dizeleri için değil C dizeleri için kullanıldığından, karakterlerin kesilmesiyle garip sorunlar bulacaksınız . Düzeltme, .size()
sınıf yöntemini kullanmaktır std::string
.
sHaystack.replace(sHaystack.find(sNeedle), sNeedle.size(), sReplace);
Bu, sHaystack inline'ın yerini alıyor - buna bir = ataması yapmaya gerek yok.
Örnek kullanım:
std::string sHaystack = "This is %XXX% test.";
std::string sNeedle = "%XXX%";
std::string sReplace = "my special";
sHaystack.replace(sHaystack.find(sNeedle),sNeedle.size(),sReplace);
std::cout << sHaystack << std::endl;
wstring myString = L"Hello $$ this is an example. By $$.";
wstring search = L"$$";
wstring replace = L"Tom";
for (int i = myString.find(search); i >= 0; i = myString.find(search))
myString.replace(i, search.size(), replace);
Hızlı bir şekilde yapmak istiyorsanız, iki tarama yaklaşımı kullanabilirsiniz. Sahte kod:
Bunun yerinde bir algo için optimize edilip edilemeyeceğinden emin değilim.
Ve bir C ++ 11 kod örneği ama ben sadece bir karakter arar.
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
void ReplaceString(string& subject, char search, const string& replace)
{
size_t initSize = subject.size();
int count = 0;
for (auto c : subject) {
if (c == search) ++count;
}
size_t idx = subject.size()-1 + count * replace.size()-1;
subject.resize(idx + 1, '\0');
string reverseReplace{ replace };
reverse(reverseReplace.begin(), reverseReplace.end());
char *end_ptr = &subject[initSize - 1];
while (end_ptr >= &subject[0])
{
if (*end_ptr == search) {
for (auto c : reverseReplace) {
subject[idx - 1] = c;
--idx;
}
}
else {
subject[idx - 1] = *end_ptr;
--idx;
}
--end_ptr;
}
}
int main()
{
string s{ "Mr John Smith" };
ReplaceString(s, ' ', "%20");
cout << s << "\n";
}
std::string replace(std::string base, const std::string from, const std::string to) {
std::string SecureCopy = base;
for (size_t start_pos = SecureCopy.find(from); start_pos != std::string::npos; start_pos = SecureCopy.find(from,start_pos))
{
SecureCopy.replace(start_pos, from.length(), to);
}
return SecureCopy;
}
Benim dize sadece bir kez yeniden boyutlandırılması gerektiğini göz önünde bulundurarak kendi uygulama, sonra değiştirme olabilir.
template <typename T>
std::basic_string<T> replaceAll(const std::basic_string<T>& s, const T* from, const T* to)
{
auto length = std::char_traits<T>::length;
size_t toLen = length(to), fromLen = length(from), delta = toLen - fromLen;
bool pass = false;
std::string ns = s;
size_t newLen = ns.length();
for (bool estimate : { true, false })
{
size_t pos = 0;
for (; (pos = ns.find(from, pos)) != std::string::npos; pos++)
{
if (estimate)
{
newLen += delta;
pos += fromLen;
}
else
{
ns.replace(pos, fromLen, to);
pos += delta;
}
}
if (estimate)
ns.resize(newLen);
}
return ns;
}
Kullanım örneğin şöyle olabilir:
std::string dirSuite = replaceAll(replaceAll(relPath.parent_path().u8string(), "\\", "/"), ":", "");
Ben sadece C ++ öğreniyorum, ama daha önce yayınlanan kod bazı düzenleme, muhtemelen böyle bir şey kullanmak istiyorum. Bu size 1 veya daha fazla örneği değiştirme esnekliği sağlar ve ayrıca başlangıç noktasını belirlemenizi sağlar.
using namespace std;
// returns number of replacements made in string
long strReplace(string& str, const string& from, const string& to, size_t start = 0, long count = -1) {
if (from.empty()) return 0;
size_t startpos = str.find(from, start);
long replaceCount = 0;
while (startpos != string::npos){
str.replace(startpos, from.length(), to);
startpos += to.length();
replaceCount++;
if (count > 0 && replaceCount >= count) break;
startpos = str.find(from, startpos);
}
return replaceCount;
}
Bunu kullanmak daha da iyi olabilir
void replace(string& input, const string& from, const string& to)
{
while(true)
{
size_t startPosition = input.find(from);
if(startPosition == string::npos)
break;
input.replace(startPosition, from.length(), to);
}
}