无法理解此代码中使用的 for 循环
Cannot understand the for loops used in this code
当我遇到这个用 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"
第二个循环搜索字符串 s
中出现的所有 t
(每次搜索都从找到的前一次出现的位置 pos
开始)。只要找到一个元素,它就会:
s[pos + t.length() / 2] = '?';
r.push_back(pos + t.length() / 2);
push_back()
存储在整数向量中找到的每个出现的中间位置。
第三个循环迭代这个存储位置的向量并打印元素(位置计数从 0 开始,+1 移动打印位置,就好像计数从 1 开始一样)。
只是 运行 在其中插入输出 pf 中间结果的代码。
这是一个演示程序。
#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"
。
在位置 0 处找到单词 "one"
。此语句
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
有助于阅读。
首先,让我们跳过正文,只关注循环本身:
for (size_t pos = 0; (pos = s.find(t, pos)) != string::npos;) {
}
所有for
循环都可以看作是while
循环,while
循环可能更容易理解和理解,所以我们将其转换为这样的[=21] =]循环:
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);
}
现在循环本身很简单,观察它我们发现基本上是尝试在字符串 s
中找到子字符串 t
。只要在 s
.
中找到子字符串 t
,循环就会继续
既然我们解构了循环本身,让我们看一下循环体及其作用:
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] = '?';
将s
中子串t
的中间字符替换为字符'?'
.
第二条语句
r.push_back(new_pos);
将 '?'
的位置推入向量 r
。
现在我们终于把内循环(上面解释的)放到外循环的上下文中:
for (string t: {"twone", "one", "two"})
这是一个 range-based for
loop,它循环遍历 :
右侧容器中的所有元素。也就是说,循环将迭代三次,t
依次等于 "twone"
、"one"
和 "two"
。
所以循环会在字符串s
中搜索"twone"
、"one"
和"two"
,替换子字符串的中间字符("twone"
, "one"
and "two"
) inside s
with a single '?'
character, and push the position of that '?'
character into the vector r.
例如,如果 s
中的输入是 "someone with the number two"
,则结果将是字符串 "someo?e with the number t?o"
,向量 r
应包含值 5
和 25
(由于 + 1
,将打印为 6
和 26
)。
Here's an example 正是如此。
当我遇到这个用 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"
第二个循环搜索字符串 s
中出现的所有 t
(每次搜索都从找到的前一次出现的位置 pos
开始)。只要找到一个元素,它就会:
s[pos + t.length() / 2] = '?';
r.push_back(pos + t.length() / 2);
push_back()
存储在整数向量中找到的每个出现的中间位置。
第三个循环迭代这个存储位置的向量并打印元素(位置计数从 0 开始,+1 移动打印位置,就好像计数从 1 开始一样)。
只是 运行 在其中插入输出 pf 中间结果的代码。
这是一个演示程序。
#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"
。
在位置 0 处找到单词 "one"
。此语句
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
有助于阅读。
首先,让我们跳过正文,只关注循环本身:
for (size_t pos = 0; (pos = s.find(t, pos)) != string::npos;) {
}
所有for
循环都可以看作是while
循环,while
循环可能更容易理解和理解,所以我们将其转换为这样的[=21] =]循环:
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);
}
现在循环本身很简单,观察它我们发现基本上是尝试在字符串 s
中找到子字符串 t
。只要在 s
.
t
,循环就会继续
既然我们解构了循环本身,让我们看一下循环体及其作用:
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] = '?';
将s
中子串t
的中间字符替换为字符'?'
.
第二条语句
r.push_back(new_pos);
将 '?'
的位置推入向量 r
。
现在我们终于把内循环(上面解释的)放到外循环的上下文中:
for (string t: {"twone", "one", "two"})
这是一个 range-based for
loop,它循环遍历 :
右侧容器中的所有元素。也就是说,循环将迭代三次,t
依次等于 "twone"
、"one"
和 "two"
。
所以循环会在字符串s
中搜索"twone"
、"one"
和"two"
,替换子字符串的中间字符("twone"
, "one"
and "two"
) inside s
with a single '?'
character, and push the position of that '?'
character into the vector r.
例如,如果 s
中的输入是 "someone with the number two"
,则结果将是字符串 "someo?e with the number t?o"
,向量 r
应包含值 5
和 25
(由于 + 1
,将打印为 6
和 26
)。
Here's an example 正是如此。