【问题标题】:Parsing a string with spaces [duplicate]解析带有空格的字符串[重复]
【发布时间】:2016-08-03 04:12:55
【问题描述】:

我在文件中有行,行中的每个字段都用空格分隔。这是一条线的简化示例:

208 "Person" "Anne Myers" "unsigned long" "hello" -1 false false false

在单个字段中,一些单词用空格分隔。即“安妮迈尔斯”。这是解析的问题。

有什么建议吗?输出应该是 9 个字段以供进一步处理。 在我的情况下,用某些字符替换字段中的空格是不可行的。

编辑:所有行都遵循相同的字段顺序。

【问题讨论】:

  • 所有行都遵循相同的字段顺序和类型吗?如果是这样,您可以使用正则表达式。
  • @Sergey 离开正则表达式
  • 这种情况下应该输出什么。
  • 只需使用解析器生成器,如果这太过分了。只需要写一个解析器!
  • 给我一个字符,如果它是引号,请将其添加到我的字段中,我真的不在乎它是什么。现在如果我遇到一个空格。我的领域已准备好发货。所以让我们这样做并开始另一个领域。重复!

标签: c++ string parsing


【解决方案1】:

一个可能的起点是重载operator>> 以正确读取这种格式的数据的类型:

class field { 
    std::string content;
public:
    friend std::istream &operator>>(std::istream &is, field &f) { 
        char ch;

        // skip whitespace, then read one character
        is >> ch;

        // If it's a quote, read to the next quote
        if (ch == '"')
            std::getline(is, f.content, '"');
        else {
            // otherwise put it back, and read until white-space:
            is.unget();
            std::getline(is, f.content);
        }
        return is;
    }

    // While we're at it, I'm going to define output so we can see what was 
    // read in a single field easily:
    friend std::ostream &operator<<(std::ostream &os, field const &f) { 
        return os << "[" << f.content << "]";
    }
};

然后我们可以为单行定义一个记录类型,将这种类型用于相应的字段:

struct foo { 
    int a;
    field b;
    field c;
    field d;
    field e;
    int f;
    bool g, h, i;

    friend std::istream &operator>>(std::istream &is, foo &f) { 
        return is >> std::boolalpha 
                  >> f.a 
                  >> f.b 
                  >> f.c 
                  >> f.d 
                  >> f.e 
                  >> f.f 
                  >> f.g 
                  >> f.h 
                  >> f.i;
    }

    friend std::ostream &operator<<(std::ostream &os, foo &f) { 
        return os << std::boolalpha 
                  << f.a << " " 
                  << f.b 
                  << f.c 
                  << f.d 
                  << f.e << " " 
                  << f.f  << " "
                  << f.g << " " 
                  << f.h << " " 
                  << f.i;
    }
};

然后我们可以测试读写一条记录:

int main() { 
    std::istringstream in
        { R"(208 "Person" "Anne Myers" "unsigned long" "hello" -1 false false false)" };

    foo f;

    in >> f;
    std::cout << f;
}

结果:

208 [Person][Anne Myers][unsigned long][hello] -1 false false false

这不会(当前)尝试处理还包含引号的字段。这可以使用类似 C 的约定(我们用反斜杠转义引号)或类似 CSV 的约定(通过在输入中连续放置两个引号来包含一个引号)。

例如:

"Bill said: ""Go away""!"

...将被解析为一个字段,包含文本:

Bill said: "Go away"!

添加任何一个都相当容易,但您还没有说要支持哪个(如果有的话),所以我暂时省略了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-07
    • 2012-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多