[当我遇到用C ++编写的代码片段时,我正在尝试解决问题的方法:
string s;
cin >> s;
vector<int> r;
for (string t: {"twone", "one", "two"}) {
for (size_t pos = 0; (pos = s.find(t, pos)) != string::npos;) {
s[pos + t.length() / 2] = '?';
r.push_back(pos + t.length() / 2);
}
}
cout << r.size() << endl;
for (auto rr: r)
cout << rr + 1 << " ";
cout << endl;
我是该语言的新手,无法理解第二(嵌套)for循环和第三for循环中发生的情况。有人可以帮助我理解吗?
第一和第三循环是range-based for loops。
第一个循环遍历字符串容器。因此,t
依次取值"twone"
,"one"
和"two"
第二个循环搜索字符串t
中所有s
的出现(每个搜索都从找到的上一个出现的位置pos
开始)。只要找到一个元素就可以:
s[pos + t.length() / 2] = '?';
r.push_back(pos + t.length() / 2);
push_back()
存储在整数矢量中发现的每个事件的中间位置。
第三个循环遍历此存储位置的向量并打印元素(位置计数从0开始,+ 1偏移打印位置,就好像计数从1开始。
只需运行插入中间结果输出的代码。
这里是演示程序。
#include <iostream>
#include <string>
#include <vector>
int main()
{
std::string s;
std::cin >> s;
std::vector<int> r;
for ( const std::string &t : { "twone", "one", "two" } )
{
for ( std::string::size_type pos = 0; (pos = s.find( t, pos ) ) != std::string::npos; )
{
s[pos + t.length() / 2] = '?';
std::cout << pos << ": " << s << '\n';
r.push_back( pos + t.length() / 2 );
}
}
std::cout << r.size() << '\n';
for ( const auto &rr: r ) std::cout << rr + 1 << " ";
std::cout << '\n';
}
假设用户输入了字符串onetwoone
。因此,内部循环会在输入的字符串中依次搜索单词“ twone”,“ one”,“ two”的所有出现。
对于给定的字符串,找不到单词"twone"
。
单词"one"
位于位置0。此语句
s[pos + t.length() / 2] = '?';
在输入的字符串中找到的单词的中间字符,用符号'?'
。
因此,此添加的语句
std::cout << pos << ": " << s << '\n';
输出
0: o?etwoone
[' (数字1)存储在向量中。
然后在循环中第二次找到单词"one"
。再次将找到的单词的中间字符替换为'?'
。所以这条语句
std::cout << pos << ": " << s << '\n';
输出
6: o?etwoo?e
[' (数字7)存储在向量中。
所以目前,我们有以下输出
0: o?etwoone
6: o?etwoo?e
不再找到单词"one"
。
单词"two"
在给定的字符串中仅出现一次。所以输出是
3: o?et?oo?e
'?'
等于4的位置存储在向量中。
现在,我们有以下输出
0: o?etwoone
6: o?etwoo?e
3: o?et?oo?e
由内部循环产生。
因此,在输入的字符串中出现了三个单词。
因此这些陈述
std::cout << r.size() << '\n';
for ( const auto &rr: r ) std::cout << rr + 1 << " ";
输出
3
2 8 5
最后一个值对应于表达式rr + 1
,即符号'?'
加1的存储位置。
尝试理解复杂代码的主要方法之一就是尝试对其进行简化。它还有助于了解所涉及功能的作用,因此a reference to std::string::find
有助于阅读。
首先,让我们跳过身体,只专注于循环本身:
std::string::find
[所有for (size_t pos = 0; (pos = s.find(t, pos)) != string::npos;) {
}
循环都可以看作是for
循环,while
循环可能更容易理解和遵循,因此我们将其转换为这样的while
循环:
while
这可能无济于事,因为这种情况很可能很难理解,因此我们也将其简化:
size_t pos = 0;
while (pos = s.find(t, pos)) != string::npos)
{
}
然后可以进一步简化size_t pos = 0;
pos = s.find(t, pos);
while (pos != string::npos)
{
pos = s.find(t, pos);
}
的初始化:
pos
现在循环本身很简单,通过查看它,我们发现基本上可以尝试在字符串size_t pos = s.find(t);
while (pos != string::npos)
{
pos = s.find(t, pos);
}
内找到子字符串t
。只要在s
中找到子字符串t
,循环就会继续。
现在我们解构了循环本身,让我们看一下循环体及其作用:
s
首先让我们将公共子表达式提取到一个临时变量中:
s[pos + t.length() / 2] = '?'; r.push_back(pos + t.length() / 2);
第一句话
auto new_pos = pos + t.length() / 2; s[new_pos] = '?'; r.push_back(new_pos);
用字符
s[new_pos] = '?';
替换t
内子字符串s
的中间字符。
第二条陈述
'?'
将
r.push_back(new_pos);
的位置插入向量'?'
。
现在,我们将内部循环(如上所述)放入外部循环的上下文中:
r
这是一个
for (string t: {"twone", "one", "two"})
,它循环遍历range-basedfor
loop右侧容器中的所有元素。也就是说,循环将迭代3次,其中for
依次等于:
,t
和"twone"
。
因此循环将在字符串"one"
中搜索"two"
,"twone"
和"one"
,替换"two"
中的子字符串的中间字符(s
,"twone"
和"one"
) ]加上一个"two"
字符,然后将该s
字符的位置推入向量r。
例如,如果'?'
中的输入为'?'
,则结果将为字符串s
,向量"someone with the number two"
应包含值"someo?e with the number t?o"
和r
(将打印为[ C0]和5
,因为25
)。
[6
完全是这样。