【问题标题】:Regex expression doesn't recognize dot at end of word - Regex (C++)正则表达式无法识别词尾的点 - 正则表达式 (C++)
【发布时间】:2023-01-16 23:28:30
【问题描述】:

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

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

在线上:

W.W.斯内德 0000574 10.0

(要清楚:目的是使任何带有字符 [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 之类的链接似乎没有回答我的问题。

【问题讨论】:

  • 第二个(非可选)字符组 ([]) 中不允许有 . 吗? It works 如果我只是添加缺少的点。
  • 你想从输入中得到什么?输入的不同字段是什么?你为什么决定尝试用正则表达式解析它?您还尝试过哪些其他解析输入的方法?我忍不住认为解析整行的正则表达式太复杂和矫枉过正,而且将无法维护。
  • 它没有意义,因为它应该检测名称。可以写下他们的首字母,给出一个输入词 (W.W.),或者写出它们,给出一个或多个:Wesley (William)。虽然考虑到正则表达式的意图有点违反直觉,但在第二个字符组中添加一个点确实有效,所以谢谢你。
  • @Someprogrammerdude 输入仅包含如上所示的行。我正在使用正则表达式来提取不同的部分并将它们相应地存储在一个类对象中,然后我可以用它来对它们进行排序,例如,等级,这是最后一个数字。使用正则表达式是否有点矫枉过正?我知道正则表达式效率不高,但真的想不出更好的方法……谢谢!
  • 就像在本站点的问题中几乎每次使用正则表达式一样,在没有正则表达式的情况下解析输入几乎肯定比使用(只写)正则表达式更简单且更易于维护。

标签: c++ regex perl


【解决方案1】:

空格分隔的数据只是常见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;
}

[参见示例here]

一旦将值分离为字符串向量,就可以将数值转换为它们的实际类型(例如使用std::stod)并存储到合适的对象中。


当然,这不能以优雅的方式处理其中包含空格的名称,但可以在更高级别处理(通过检查结果向量的大小,并知道最后两个元素应该始终是特殊数字,并且其余的是名字)。

另一方面,问题中的正则表达式根本不处理它。 :)

【讨论】:

  • 这当然看起来更不容易出错并且效率更高。谢谢!
  • ... 除了您必须编写检查以确保结果数组中的每个文本都是您想要的格式。上面的解决方案成功地解析了1 2 3 4 例如...现在,获得一个干净的正则表达式或编写 4 段不同的代码,每段代码控制表中 4 项的特定格式会更快吗?
【解决方案2】:

在您的正则表达式中,整个 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 个捕获组之外,如果您需要将其转换为另一种类型,则对文本有一些保证。

【讨论】:

  • 第三个是为我做的!感谢您的帮助
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多