C++14提取带引号的字符串,包括引号本身

3

让我来处理一个字符串:

string tstring = "Some arbitrarily long string which has \"double quotes\" which has to be printed verbatim";

我尝试使用stringstreams和quoted来提取单词。
stringstream stream(tstring);
string tepm;
while(stream >> std::quoted(temp))
    cout << temp << endl;

但是上面的内容跳过了引号所在的字符串。
Some
arbitrarily
.
.
double quotes
.
.
verbatim

我希望完全打印包含引号的引用字符串。

Some
arbitrarily
.
.
"double quotes"
.
.
verbatim

如何使用引用函数来完成此操作?如果不可能,是否有更好的方法来完成此操作(当然,除了逐个字符阅读并自己完成所有工作)。

编辑:

这是所请求的 MCVE。

#include <iostream>
#include <string>
#include <sstream>
#include <iomanip>

using namespace std;

int main(){
    string sspace = "Hi this is \"Real Madrid\"";
    stringstream stream(sspace);
    string fpart;
    while(stream >> quoted(fpart)){
        cout << fpart << endl;
    }
    return 0;
}

std::quoted会移除引号。请参见http://en.cppreference.com/w/cpp/io/manip/quoted。`quoted`旨在将带引号的子字符串视为单个项,忽略空格。 - 3Dave
@DavidLively 我知道 quoted 是在删除引号和输出,但有没有办法找出它是否被引用并保留引号和字符串? - Vikash Balasubramanian
嗯...实际上,quoted的定义似乎表明,在像stream >> std::quoted(temp)这样的输入中,转义引号应该被保留。你能否发布一个完整、可编译的简短示例? - 3Dave
@DavidLively 我已经添加了 MCVE,如果您想要检查的话。 - Vikash Balasubramanian
2个回答

2

当用于输入时,std::quoted 会从字符串中删除未转义的引号并取消转义已转义的引号。因此,像这样的字符串:

"some \"string with\" inner quotes"

当阅读时,它会变成这样:

some "string with" inner quotes

但要使这个工作正常,字符串必须在流中被引用和转义。如果您这样做:

std::string str = "string \"with some\" quotes";
std::stringstream ss (str);
std::cout << "stream contents: " << ss.str() << std::endl;

实际的流内容将是:
string "with some" quotes

在声明str时进行的转义并不会出现在流中,它只是为了解析器而存在。如果您希望它在输出流中完全按照此方式编写,则需要改为以下方式:

std::string str = "\"string \\\"with some\\\" quotes\"";

或者更好的方法是:
std::string str = "string \"with some\" quotes";
ss << std::quoted(str);

并让 std::quoted 完成它的工作。


很奇怪的是,尽管这似乎有效,但它与cppreference.com示例上的示例直接冲突。(http://en.cppreference.com/w/cpp/io/manip/quoted) - 3Dave
你说得没错,但我想把引用的字符串存储在一个单独的变量中,使用你的方法该怎么做呢?或者至少我需要一种方法来跳过字符串中除引号内部以外的空格。 - Vikash Balasubramanian
@DavidLively 它与该示例有何冲突? @VikashB 您可以使用 quoted 将其写入 stringstream 中,然后使用 stream.str() 获取流的内容。 - Ionut

2

我认为在这里 std::quoted 不是正确的工具,因为没有简单的方法告诉你下一个字符串是否被剥离了引号(默认情况下它会丢弃你的分隔符,即'\"'

我认为我们可以安全地回退到 std::stringfind 方法。

  • 包含一个子程序来打印所有不在引号内的单词(以空格分隔)
  • 利用 find 持续读取直到下一个引号字符:

完整代码:

void PrintUnquoted(std::string _in)
{
    std::istringstream ss(_in);
    std::string temp;
    while(ss >> temp)
    {
        std::cout << temp << '\n';
    }
}

int main(){
    std::string sspace = "Hi this is \"Real Madrid\" etc.";
    size_t start = 0;
    size_t nextQuote = 0;
    while(nextQuote = sspace.find('\"', start), nextQuote != std::string::npos)
    {
        size_t endQuote = sspace.find('\"', nextQuote+1);
        if (endQuote == std::string::npos)
        {
            throw std::logic_error("Unmatched quotes");
        }

        PrintUnquoted(sspace.substr(start, nextQuote-start));
        std::cout << sspace.substr(nextQuote, endQuote-nextQuote+1) << std::endl;
        start = endQuote+1;
    }
    if (start < sspace.size())
    {
        PrintUnquoted(sspace.substr(start));
    }
    return 0;
}

演示

如果您需要在变量中存储带引号的字符,可以使用以下代码:

 std::cout << sspace.substr(nextQuote, endQuote-nextQuote+1) << std::endl;

应该能够轻松修改以获得这个结果。

不错,我也考虑过这个方案,但我的代码变得非常复杂而混乱,所以想尝试其他选项。 - Vikash Balasubramanian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接