无法理解此代码中使用的for循环

问题描述 投票:1回答:3

[当我遇到用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循环中发生的情况。有人可以帮助我理解吗?

c++ for-loop vector std
3个回答
1
投票

第一和第三循环是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开始。


0
投票

只需运行插入中间结果输出的代码。

这里是演示程序。

#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的存储位置。


0
投票

尝试理解复杂代码的主要方法之一就是尝试对其进行简化。它还有助于了解所涉及功能的作用,因此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-based for 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完全是这样。

© www.soinside.com 2019 - 2024. All rights reserved.