c++ - C++:如何使用正则表达式从字符串中提取单词

标签 c++ regex string

我想从字符串中提取单词。我可以想到两种方法可以完成此任务:


用定界符提取。
通过单词模式搜索提取。


在深入探讨问题之前,我想澄清一下,尽管我确实询问了提取方法及其实现,但问题的主要焦点是正则表达式。不是实现。

我要匹配的单词可以包含撇号(例如“ Do n't”),可以在双引号或单引号(撇号)(例如“ Hello”和“ world”)之内,以及两者的组合(例如“ Didn” t”和“不会”)。它们还可以包含数字(例如“ 2017”和“ U2”)以及下划线和连字符(例如“ hello_world”和“ time-turner”)。单词中的撇号,下划线和连字符必须由其他单词字符包围。最后的要求是,包含随机非单词字符(例如“ Goodmor¨+%g。”)的字符串仍应将所有单词字符识别为单词。

从中提取单词的示例字符串以及我想要的结果看起来像什么:


"Hello, world!"应该导致"Hello""world"
"Aren't you clever?"应该导致"Aren't""you""clever"
"'Later', she said."应该导致"Later""she""said"
"'Maybe 5 o'clock?'"应该导致"Maybe""5""o'clock"
"In the year 2017 ..."应导致"In""the""year""2017"
"G2g, cya l8r"应该导致"G2g""cya""l8r"
"hello_world.h"应该导致"hello_world""h"
"Hermione's time-turner."应该导致"Hermione's""time-turner"
"Good mor~+%g."应该导致"Good""mor""g"
"Hi' Testing_ Bye-"应该导致"Hi""Testing""Bye"


因为-就我所知-我提出的两种方法需要完全不同的解决方案,因此我将问题分为两部分-每种方法一个。

1.用定界符提取

这是我大部分时间用于开发的方法,并且找到了部分可行的解决方案-但是,我怀疑我使用的正则表达式不是非常有效。我的解决方案是这样的(使用Boost.Regex,因为它的Perl语法支持回头看):

#include <string>
#include <vector>
#include <iostream>
#include <boost/regex.hpp>



std::vector<std::string> phrases({  "Hello, world!", "Aren't you clever?",
                                    "'Later', she said.", "'Maybe 5 o'clock?'",
                                    "In the year 2017 ...", "G2g, cya l8r",
                                    "hello_world.h", "Hermione's time-turner.",
                                    "Good mor~+%g.", "Hi' Testing_ Bye-"});
std::vector<std::string> words;

boost::regex delimiterPattern("^'|[\\W]*(?<=\\W)'+\\W*|(?!\\w+(?<!')'(?!')\\w+)[^\\w']+|'$");
boost::sregex_token_iterator end;
for (std::string phrase : phrases) {
    boost::sregex_token_iterator phraseIter(phrase.begin(), phrase.end(), delimiterPattern, -1);

    for ( ; phraseIter != end; phraseIter++) {
        words.push_back(*phraseIter);
        std::cout << words[words.size()-1] << std::endl;
    }
}


这个解决方案最大的问题是我的正则表达式,我认为它看起来太复杂了,可能会做得更好。它也不能正确匹配单词末尾的撇号-如示例3中所示。这是带有regex和示例字符串的链接到regex101.com:Delimiter regex

2.通过单词模式搜索提取

我自己没有花太多时间去追求这条路,主要是将它作为替代方案,因为我的部分解决方案不一定是最好的解决方案。关于如何完成此操作,我的建议是按照重复搜索字符串的方式进行操作,在运行时从字符串中删除每个匹配项,直到不再有匹配项为止。我为此方法使用了一个正则表达式,但仍希望输入:"[A-Za-z0-9]+(['_-]?[A-Za-z0-9]+)?"。这是带有regex和示例字符串的regex101.com的链接:Word pattern regex

我想再次强调,我首先要在我的正则表达式上输入内容,但也希望对实现这些方法有所帮助。



编辑:感谢@Galik指出所有格可以以撇号结尾。与它们相关的撇号可以在定界符中匹配,而不必在单词模式中匹配(即"The kids' toys"应该导致"The""kids""toys")。

最佳答案

您可以使用

[^\W_]+(?:['_-][^\W_]+)*


请参见regex demo

图案细节:


[^\W_]+-非字字符和_以外的一个或多个字符(与字母数字字符匹配)
(?:-一个非捕获组的开始,该组仅将子模式和匹配项分组:


['_-]-一个'_-
[^\W_]+-1个以上字母数字字符

)*-将组重复零次或多次。


C++ demo

std::regex r(R"([^\W_]+(?:['_-][^\W_]+)*)");
std::string s = "Hello, world! Aren't you clever? 'Later', she said. Maybe 5 o'clock?' In the year 2017 ... G2g, cya l8r hello_world.h Hermione's time-turner. Good mor~+%g. Hi' Testing_ Bye- The kids' toys";
for(std::sregex_iterator i = std::sregex_iterator(s.begin(), s.end(), r);
                         i != std::sregex_iterator();
                         ++i)
{
    std::smatch m = *i;
    std::cout << m.str() << '\n';
}

关于c++ - C++:如何使用正则表达式从字符串中提取单词,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45070539/

相关文章:

c++ - 以实参作为模板形参的模板化函数指针

css - 将选择器添加到 css 文件中的每一行

c++ - 如何比较类的数据成员的名称而不是它们的值

java - 如何使用 java 将数字点 (.) 替换为逗号 (,)

javascript - 如何拆分和添加字符串中的各个值?

c++ - 计算 AABB(轴对齐边界框)碰撞

c++ - 用于映射一对一关系的 STL 类型?

c++ - 错误 : expected primary-expression before '.' token

python - django 正则表达式只匹配字母数字而不是下划线

regex - 使用 sed 打印每个匹配模式的第一行出现次数