perl Regex表达式无法识别单词末尾的点- Regex(C++)

pbgvytdp  于 2023-01-17  发布在  Perl
关注(0)|答案(2)|浏览(135)

我尝试使用以下regex表达式从文件中读取一行:

^([A-z.]+?\\s?[A-z]+)\\s([A-z]+)\\s(\\d{7})\\s(\\d?\\d.\\d)$

在线上:
斯内德0000574 10.0
(To明确:目的是使任何带有字符[a-z]、[A-Z]或点的单词与[A-z.]+部分匹配。)
然而,正则表达式不能识别W.W.中的第二个点,这让我觉得很奇怪。方括号和+组合在一起不就意味着它们内部的任何字符都可以接受,直到(这里)遇到空格吗?我发现了一个正则表达式,它确实可以工作,但不那么优雅:

^([A-z.]+[.\\s?[A-z]+)\\s([A-z]+)\\s(\\d{7})\\s(\\d?\\d.\\d)$

我希望他们能找到一个优雅的解决方案。能听听你的意见就好了。
RegEx - Not parsing dot(.) at the end of a sentence这样的链接似乎没有回答我的问题。

vuktfyat

vuktfyat1#

空格分隔的数据只是常见CSV (Comma Separated Values)的一个不同变体。有许多方法可以用任意分隔符分隔字符串,但在C++中使用空格实际上非常容易:

std::vector<std::string> separate_on_space(std::string const& input)
{
    std::vector<std::string> output;
    std::istringstream iss(input);

    // Copy all space-separated "words" from the input to the vector
    std::copy(std::istream_iterator<std::string>(iss), // Begin iterator
              std::istream_iterator<std::string>(),    // End iterator
              std::back_inserter(output));             // Destination iterator

    return output;
}

[See示例here ]
一旦将值分隔为字符串向量,就可以将数值转换为它们的实际类型(例如使用std::stod)并存储到合适的对象中。
当然,这并不能很好地处理名称中包含空格的情况,但可以在更高的层次上处理(通过检查结果向量的大小,并知道最后两个元素应该始终是特殊数字,其余的是名称)。
另一方面,问题中的正则表达式根本不处理它。:)

rggaifut

rggaifut2#

在你的正则表达式中,整个W.W. Sneijder被捕获在第一组中。看看你的正则表达式,我怀疑你是故意这样做的。
我想你要的正则表达式是^([A-z.]+?\s?[A-z]+)\s(\d{7})\s(\d?\d.\d)$
或者,如果您希望Sneijder出现在第二个捕获中:^([A-z.]+?)\s([A-z]+)\s(\d{7})\s(\d?\d.\d)$ .
...或者您可能需要^([A-z.]+?\s?[A-z]*)\s([A-z]+)\s(\d{7})\s(\d?\d.\d)$(在第一个捕获组中使用*而不是+)。
^([A-z.]+?(?:\s[A-z]+)?)\s([A-z]+)\s(\d{7})\s(\d?\d.\d)$(可选空格+文本,同样在第一捕获组中)。
所有4个表达式都应该与您的测试字符串匹配,但在其他测试字符串上的行为不同。
正则表达式当然也有改进,比如确保字符串不以.开头。
只要您触及每个捕获组的内部,而不是跨捕获组的逻辑,就可以让正则表达式管理您想要的任何级别的控制,这不会影响文本解析之后的代码。
它总是有4个捕获组,除了我上面发布的第一个正则表达式只有3个捕获组,如果你需要将它转换为另一种类型,对文本有一些保证。

相关问题