C ++ có thể thay thế một phần của chuỗi bằng một chuỗi khác không?
Về cơ bản, tôi muốn làm điều này:
QString string("hello $name");
string.replace("$name", "Somename");
Nhưng tôi muốn sử dụng các thư viện Standard C ++.
C ++ có thể thay thế một phần của chuỗi bằng một chuỗi khác không?
Về cơ bản, tôi muốn làm điều này:
QString string("hello $name");
string.replace("$name", "Somename");
Nhưng tôi muốn sử dụng các thư viện Standard C ++.
Câu trả lời:
Có một hàm để tìm một chuỗi con trong một chuỗi ( find
) và một hàm để thay thế một phạm vi cụ thể trong một chuỗi bằng một chuỗi khác ( replace
), vì vậy bạn có thể kết hợp các chuỗi đó để có được hiệu ứng bạn muốn:
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");
Đáp lại một bình luận, tôi nghĩ replaceAll
có lẽ sẽ trông giống như thế này:
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
và to
thông qua mỗi const
tham chiếu? Chức năng của bạn from
là gì nếu không có? -1
từ tôi cho điều đó.
const
và nếu tôi viết một phương thức tiện ích như thế này thì tôi sẽ chỉ gọi nó nếu tôi biết thay thế là hợp lệ
const
là coi thường một trong những công cụ tốt nhất của C ++. Truyền cho mỗi const
tham chiếu phải là chế độ mặc định cho các tham số chức năng. (FTR, không có const
, bạn thậm chí không thể chuyển chuỗi ký tự chuỗi cho hàm của mình, vì bạn không thể liên kết tạm thời với các const
tham chiếu không . Vì vậy, hàm này thậm chí sẽ không thực hiện những gì nó được viết.)
Với C ++ 11, bạn có thể sử dụng std::regex
như vậy:
#include <regex>
...
std::string string("hello $name");
string = std::regex_replace(string, std::regex("\\$name"), "Somename");
Dấu gạch chéo kép là cần thiết để thoát một ký tự thoát.
std::regex_replace
không chấp nhận chuỗi của Qt.
string
bằng string.toStdString()
.
String
thành std::string
, vì câu hỏi không liên quan đến Qt. Vui lòng xem xét việc đó - Tôi sẽ vui lòng đưa ra câu trả lời của bạn sau đó.
R"(\$name)"
thay vì "\\$name"
.
std::string
có một replace
phương pháp, đó là những gì bạn đang tìm kiếm?
Bạn có thể thử:
s.replace(s.find("$name"), sizeof("$name") - 1, "Somename");
Tôi đã không thử bản thân mình, chỉ cần đọc tài liệu trên find()
và replace()
.
Để có chuỗi mới được trả về, hãy sử dụng:
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;
}
Nếu bạn cần hiệu suất, đây là một chức năng được tối ưu hóa để sửa đổi chuỗi đầu vào, nó không tạo ra một bản sao của chuỗi:
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();
}
}
Các xét nghiệm:
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;
Đầu ra:
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
Có, bạn có thể làm điều đó, nhưng bạn phải tìm vị trí của chuỗi đầu tiên với thành viên find () của chuỗi, sau đó thay thế bằng thành viên thay thế ().
string s("hello $name");
size_type pos = s.find( "$name" );
if ( pos != string::npos ) {
s.replace( pos, 5, "somename" ); // 5 = length( $name )
}
Nếu bạn đang có kế hoạch sử dụng Thư viện tiêu chuẩn, bạn thực sự nên nắm giữ một bản sao của cuốn sách Thư viện chuẩn C ++ bao gồm tất cả những thứ này rất tốt.
Tôi thường sử dụng cái này:
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;
}
Nó liên tục gọi std::string::find()
để xác định vị trí xuất hiện khác của chuỗi tìm kiếm cho đến khi std::string::find()
không tìm thấy gì. Vì std::string::find()
trả về vị trí của trận đấu, chúng tôi không gặp vấn đề về việc vô hiệu hóa các vòng lặp.
Điều này nghe có vẻ như là một lựa chọn
string.replace(string.find("%s"), string("%s").size(), "Something");
Bạn có thể gói cái này trong một hàm nhưng giải pháp một dòng này nghe có vẻ chấp nhận được. Vấn đề là điều này sẽ chỉ thay đổi lần xuất hiện đầu tiên, bạn có thể muốn lặp lại nó, nhưng nó cũng cho phép bạn chèn một số biến vào chuỗi này với cùng một mã thông báo ( %s
)
str.replace(str.find("%s"), string("%s").size(), "Something");
Nếu tất cả các chuỗi là std :: string, bạn sẽ thấy các vấn đề lạ với việc cắt các ký tự nếu sử dụng sizeof()
vì nó có nghĩa là chuỗi C, không phải chuỗi C ++. Cách khắc phục là sử dụng .size()
phương thức lớp std::string
.
sHaystack.replace(sHaystack.find(sNeedle), sNeedle.size(), sReplace);
Điều đó thay thế nội tuyến sHaystack - không cần thực hiện một phép gán = trên đó.
Ví dụ sử dụng:
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);
Nếu bạn muốn làm điều đó một cách nhanh chóng, bạn có thể sử dụng phương pháp quét hai. Mã giả:
Tôi không chắc chắn nếu điều này có thể được tối ưu hóa thành một thuật toán tại chỗ.
Và một ví dụ mã C ++ 11 nhưng tôi chỉ tìm kiếm một char.
#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;
}
Việc thực hiện của riêng tôi, có tính đến chuỗi đó chỉ cần thay đổi kích thước một lần, sau đó thay thế có thể xảy ra.
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;
}
Cách sử dụng có thể là ví dụ như thế này:
std::string dirSuite = replaceAll(replaceAll(relPath.parent_path().u8string(), "\\", "/"), ":", "");
Tôi mới học C ++, nhưng chỉnh sửa một số mã được đăng trước đó, có lẽ tôi sẽ sử dụng cái gì đó như thế này. Điều này cho phép bạn linh hoạt thay thế 1 hoặc nhiều trường hợp và cũng cho phép bạn chỉ định điểm bắt đầu.
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;
}
Điều này có thể còn tốt hơn để sử dụng
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);
}
}