Чи можливо в C ++ замінити частину рядка на іншу рядок?
В основному, я хотів би це зробити:
QString string("hello $name");
string.replace("$name", "Somename");
Але я хотів би використовувати бібліотеки Standard C ++.
Чи можливо в C ++ замінити частину рядка на іншу рядок?
В основному, я хотів би це зробити:
QString string("hello $name");
string.replace("$name", "Somename");
Але я хотів би використовувати бібліотеки Standard C ++.
Відповіді:
Існує функція знайти підрядку в рядку ( find
) і функція замінити певний діапазон у рядку іншою рядком ( replace
), так що ви можете об'єднати ці, щоб отримати потрібний ефект:
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");
У відповідь на коментар, я думаю replaceAll
, мабуть, виглядатиме приблизно так:
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
і не to
передаються за const
посилання? Яка ваша функція, якщо from
її немає? -1
від мене за це.
const
і якби я написав такий корисний метод, я би назвав його, якби знав заміна була дійсною
const
- це ігнорування одного з найкращих інструментів C ++. Передача const
посилання повинна бути режимом за замовчуванням для параметрів функції. (FTR, без цього const
, ви навіть не можете передати рядкові літерали до своєї функції, тому що ви не можете прив'язувати тимчасові файли до не const
посилань. Таким чином, функція навіть не зробить те, про що було написано.)
З C ++ 11 можна використовувати std::regex
так:
#include <regex>
...
std::string string("hello $name");
string = std::regex_replace(string, std::regex("\\$name"), "Somename");
Подвійний зворотний нахил потрібен для втечі символу втечі.
std::regex_replace
не приймає рядок Qt.
string
на string.toStdString()
.
String
на std::string
, тому що питання не стосується Qt. Будь ласка, подумайте про це - я із задоволенням підтримаю вашу відповідь після цього.
R"(\$name)"
замість "\\$name"
.
std::string
має replace
метод, це те, що ви шукаєте?
Ви можете спробувати:
s.replace(s.find("$name"), sizeof("$name") - 1, "Somename");
Я ще не пробував себе, просто читав документацію на find()
та replace()
.
Щоб повернути новий рядок, використовуйте це:
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;
}
Якщо вам потрібна продуктивність, ось оптимізована функція, яка модифікує вхідний рядок, вона не створює копію рядка:
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();
}
}
Тести:
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;
Вихід:
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
Так, ви можете це зробити, але вам потрібно знайти позицію першого рядка з членом string ((find)), а потім замінити його заміною ().
string s("hello $name");
size_type pos = s.find( "$name" );
if ( pos != string::npos ) {
s.replace( pos, 5, "somename" ); // 5 = length( $name )
}
Якщо ви плануєте використовувати Стандартну бібліотеку, вам справді слід придбати копію книги «Стандартна бібліотека C ++», яка дуже добре висвітлює всі ці речі.
Я використовую в основному це:
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;
}
Він неодноразово закликає std::string::find()
знайти інші події шуканого рядка, поки std::string::find()
нічого не знайде. Оскільки std::string::find()
повертає позицію матчу, ми не маємо проблеми з вимкненням ітераторів.
Це звучить як варіант
string.replace(string.find("%s"), string("%s").size(), "Something");
Ви можете зафіксувати це у функції, але це однолінійне рішення здається прийнятним. Проблема полягає в тому, що це змінить лише перше виникнення, можливо, ви захочете перетворити його на цикл, але це також дозволяє вставити кілька змінних у цей рядок з тим же маркером ( %s
)
str.replace(str.find("%s"), string("%s").size(), "Something");
Якщо всі рядки std :: string, у вас виникнуть дивні проблеми з обрізанням символів, якщо використовується, sizeof()
тому що це призначено для C рядків, а не C ++. Виправлення полягає у використанні .size()
методу класу std::string
.
sHaystack.replace(sHaystack.find(sNeedle), sNeedle.size(), sReplace);
Це замінює вбудований sHaystack inline - не потрібно виконувати завдання = на цьому.
Приклад використання:
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);
Якщо ви хочете зробити це швидко, ви можете скористатися двома підходами сканування. Псевдокод:
Я не впевнений, чи можна це оптимізувати до альго на місці.
І приклад коду C ++ 11, але я шукаю лише одну таблицю.
#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;
}
Моя власна реалізація, беручи до уваги, що рядок потрібно змінити лише один раз, тоді заміна може статися.
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;
}
Використання може бути, наприклад, таким:
std::string dirSuite = replaceAll(replaceAll(relPath.parent_path().u8string(), "\\", "/"), ":", "");
Я тільки зараз вивчаю C ++, але редагуючи частину раніше розміщеного коду, я, мабуть, використовую щось подібне. Це дає вам можливість замінити 1 або кілька екземплярів, а також дозволяє вказати початкову точку.
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;
}
Це може бути ще краще використовувати
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);
}
}