簡體   English   中英

C ++:如何使用正則表達式從字符串中提取單詞

[英]C++: How to extract words from string with regex

我想從字符串中提取單詞。 我可以想到兩種方法可以完成此任務:

  1. 用定界符提取。
  2. 通過單詞模式搜索提取。

在深入探討問題之前,我想澄清一下,盡管我確實詢問了提取方法及其實現,但問題的主要焦點是正則表達式。 不是實現。

我要匹配的單詞可以包含撇號(例如“ Do n't”),可以在雙引號或單引號(撇號)(例如“ Hello”和“ world”)之內,也可以是兩者的組合(例如“ Didn” t”和“不會”)。 它們還可以包含數字(例如“ 2017”和“ U2”)以及下划線和連字符(例如“ hello_world”和“ time-turner”)。 單詞中的撇號,下划線和連字符必須由其他單詞字符包圍。 最后一個要求是,包含隨機非單詞字符(例如“ Goodmor¨+%g。”)的字符串仍應將所有單詞字符識別為單詞。

從中提取單詞的示例字符串以及我想要的結果看起來像什么:

  1. "Hello, world!" 應該導致"Hello""world"
  2. "Aren't you clever?" 應該導致"Aren't""you""clever"
  3. "'Later', she said." 應顯示"Later""she""said"
  4. "'Maybe 5 o'clock?'"應顯示為"Maybe""5""o'clock"
  5. "In the year 2017 ..."結果應為"In""the""year""2017"
  6. "G2g, cya l8r"應導致"G2g""cya""l8r"
  7. "hello_world.h"應導致"hello_world""h"
  8. "Hermione's time-turner." 應該導致"Hermione's""time-turner"
  9. "Good mor~+%g." 應產生"Good""mor""g"
  10. "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的鏈接: 單詞模式regex

我想再次強調,我首先要在我的正則表達式上輸入內容,但也希望對實現這些方法有所幫助。


編輯:感謝@Galik指出所有格可以以撇號結尾。 與它們相關的撇號可以在定界符中匹配,而不必在單詞模式中匹配(即, "The kids' toys"應生成"The""kids""toys" )。

您可以使用

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

參見regex演示

圖案細節

  • [^\\W_]+ -除非單詞字符和_以外的一個或多個字符(與字母數字字符匹配)
  • (?: -非捕獲組的開始,該組僅將子模式和匹配項分組:
    • ['_-] -a '_-
    • [^\\W_]+ -1+個字母數字字符
  • )* -將群組重復零次或多次。

C ++演示

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';
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM