在 C++ 中使用正则表达式标记字符串并保留定界符
Tokenize a String and Keep Delimiters Using Regular Expression in C++
我想修改给定的正则表达式以生成以下匹配项列表。我很难用语言描述问题。
我想用正则表达式匹配一组'tokens'。具体来说,我希望匹配 &&
、||
、;
、(
、)
,并且任何不包含这些字符的字符串都应该是匹配项。
我遇到的问题是区分一根管道和两根管道。我怎样才能产生所需的匹配项?非常感谢您的帮助!
表达式:
((&{2})|(\|{2})|(\()|(\))|(;)|[^&|;()]+)
测试字符串
a < b | c | d > e >> f && ((g) || h) ; i
预期匹配
a < b | c | d > e >> f
&&
(
(
g
)
||
h
)
;
i
实际匹配
a < b
|
c
|
d > e >> f
&&
(
(
g
)
||
h
)
;
i
我正在尝试为 C++ 中的程序实现自定义分词器。
示例代码
std::vector<std::string> Parser::tokenizeInput(std::string s) {
std::vector<std::string> returnTokens;
//tokenize correctly using this regex
std::regex rgx(R"S(((&{2})|(\|{2})|(\()|(\))|(;)|[^&|;()]+))S");
std::regex_iterator<std::string::iterator> rit ( s.begin(), s.end(), rgx );
std::regex_iterator<std::string::iterator> rend;
while (rit!=rend) {
std::string tokenStr = rit->str();
if(tokenStr.size() > 0 && tokenStr != " "){
//assure the token is not blank
//and push the token
boost::algorithm::trim(tokenStr);
returnTokens.push_back(tokenStr);
}
++rit;
}
return returnTokens;
}
示例驱动程序代码
//in main
std::vector<std::string> testVec = Parser::tokenizeInput(inputWithNoComments);
std::cout << "input string: " << inputWithNoComments << std::endl;
std::cout << "tokenized string[";
for(unsigned int i = 0; i < testVec.size(); i++){
std::cout << testVec[i];
if ( i + 1 < testVec.size() ) { std::cout << ", "; }
}
std::cout << "]" << std::endl;
产生的输出
input string: (cat file > outFile) || ( ls -l | grep -i )
tokenized string[(, cat file > outFile, ), ||, (, ls -l, grep -i, )]
input string: a && b || c > d >> e < f | g
tokenized string[a, &&, b, ||, c > d >> e < f, g]
input string: foo | bar || foo || bar | foo | bar
tokenized string[foo, bar, ||, foo, ||, bar, foo, bar]
我想要的输出结果
input string: (cat file > outFile) || ( ls -l | grep -i )
tokenized string[(, cat file > outFile, ), ||, (, ls -l | grep -i, )]
input string: a && b || c > d >> e < f | g
tokenized string[a, &&, b, ||, c > d >> e < f | g]
input string: foo | bar || foo || bar | foo | bar
tokenized string[foo | bar, ||, foo, ||, bar | foo | bar]
您尚未指定您使用的是哪种语言,但大多数应用程序语言都支持在此正则表达式上拆分字符串:
" *((?=($$|\|\||[;()])|(?<=$$|\|\|)|(?<=[;()])) *"
正则表达式是向前看或向后看你的条款,但环顾四周输入不会被消耗,因此分隔符将输出到结果数组。
如果你使用python,事情就简单多了;拆分此正则表达式:
" *($$|\|\||[;()]) *"
捕获的任何分隔符都将成为输出数组的一部分。
我准备了以下正则表达式并对其进行了测试,它产生的输出与您输入字符串中描述的完全相同:
(?<=&&)[^;()]*|\(|\)|(?<=\|\|)[^;()]*|;|&&|\|\||([^|;()&]+(\|[^|;()&]+)*)*
或者这个:
\(|\)|;|&&|\|\||([^|;()&]+(&[^|;()&]+|\|[^|;()&]+)*)
让我知道它是否按预期工作!
匹配项:
a < b | c | d > e >> f
&&
(
(
g
)
||
h
)
;
i
并测试于:
(cat file > outFile) || ( ls -l | grep -i )
(cat file >> outFile) && ls -l | grep -i
((file < file) || ls -l ; ls)
cat < InputFile | tr a-z A-Z | tee out1 > out2 >> out3 | asd aasdasd | asd | asd || asd | asd
a | b || c | d && a || b && d ; g &&
a && b || c > d >> e < f | g
a < b | c | d > e >> f && ((g) || h) ; i
我建议通过将 {-1,0}
传递给 sregex_token_iterator
来收集不匹配和匹配的子字符串,并使用更简单的正则表达式,如 &&|\|\||[;()]
,同时丢弃空的子字符串(这是由于找到连续匹配项时字符串的拆分方式所致):
std::regex rx(R"(&&|\|\||[();])");
std::string exp = "a < b | c | d > e >> f && ((g) || h) ; i";
std::sregex_token_iterator srti(exp.begin(), exp.end(), rx, {-1, 0});
std::vector<std::string> tokens;
std::remove_copy_if(srti, std::sregex_token_iterator(),
std::back_inserter(tokens),
[](std::string const &s) { return s.empty(); });
for( auto & p : tokens ) std::cout <<"'"<< p <<"'"<< std::endl;
见C++ demo,输出:
'a < b | c | d > e >> f '
'&&'
' '
'('
'('
'g'
')'
' '
'||'
' h'
')'
' '
';'
' i'
空字符串删除代码的特别功劳归于 。
我想修改给定的正则表达式以生成以下匹配项列表。我很难用语言描述问题。
我想用正则表达式匹配一组'tokens'。具体来说,我希望匹配 &&
、||
、;
、(
、)
,并且任何不包含这些字符的字符串都应该是匹配项。
我遇到的问题是区分一根管道和两根管道。我怎样才能产生所需的匹配项?非常感谢您的帮助!
表达式:
((&{2})|(\|{2})|(\()|(\))|(;)|[^&|;()]+)
测试字符串
a < b | c | d > e >> f && ((g) || h) ; i
预期匹配
a < b | c | d > e >> f
&&
(
(
g
)
||
h
)
;
i
实际匹配
a < b
|
c
|
d > e >> f
&&
(
(
g
)
||
h
)
;
i
我正在尝试为 C++ 中的程序实现自定义分词器。
示例代码
std::vector<std::string> Parser::tokenizeInput(std::string s) {
std::vector<std::string> returnTokens;
//tokenize correctly using this regex
std::regex rgx(R"S(((&{2})|(\|{2})|(\()|(\))|(;)|[^&|;()]+))S");
std::regex_iterator<std::string::iterator> rit ( s.begin(), s.end(), rgx );
std::regex_iterator<std::string::iterator> rend;
while (rit!=rend) {
std::string tokenStr = rit->str();
if(tokenStr.size() > 0 && tokenStr != " "){
//assure the token is not blank
//and push the token
boost::algorithm::trim(tokenStr);
returnTokens.push_back(tokenStr);
}
++rit;
}
return returnTokens;
}
示例驱动程序代码
//in main
std::vector<std::string> testVec = Parser::tokenizeInput(inputWithNoComments);
std::cout << "input string: " << inputWithNoComments << std::endl;
std::cout << "tokenized string[";
for(unsigned int i = 0; i < testVec.size(); i++){
std::cout << testVec[i];
if ( i + 1 < testVec.size() ) { std::cout << ", "; }
}
std::cout << "]" << std::endl;
产生的输出
input string: (cat file > outFile) || ( ls -l | grep -i )
tokenized string[(, cat file > outFile, ), ||, (, ls -l, grep -i, )]
input string: a && b || c > d >> e < f | g
tokenized string[a, &&, b, ||, c > d >> e < f, g]
input string: foo | bar || foo || bar | foo | bar
tokenized string[foo, bar, ||, foo, ||, bar, foo, bar]
我想要的输出结果
input string: (cat file > outFile) || ( ls -l | grep -i )
tokenized string[(, cat file > outFile, ), ||, (, ls -l | grep -i, )]
input string: a && b || c > d >> e < f | g
tokenized string[a, &&, b, ||, c > d >> e < f | g]
input string: foo | bar || foo || bar | foo | bar
tokenized string[foo | bar, ||, foo, ||, bar | foo | bar]
您尚未指定您使用的是哪种语言,但大多数应用程序语言都支持在此正则表达式上拆分字符串:
" *((?=($$|\|\||[;()])|(?<=$$|\|\|)|(?<=[;()])) *"
正则表达式是向前看或向后看你的条款,但环顾四周输入不会被消耗,因此分隔符将输出到结果数组。
如果你使用python,事情就简单多了;拆分此正则表达式:
" *($$|\|\||[;()]) *"
捕获的任何分隔符都将成为输出数组的一部分。
我准备了以下正则表达式并对其进行了测试,它产生的输出与您输入字符串中描述的完全相同:
(?<=&&)[^;()]*|\(|\)|(?<=\|\|)[^;()]*|;|&&|\|\||([^|;()&]+(\|[^|;()&]+)*)*
或者这个:
\(|\)|;|&&|\|\||([^|;()&]+(&[^|;()&]+|\|[^|;()&]+)*)
让我知道它是否按预期工作!
匹配项:
a < b | c | d > e >> f
&&
(
(
g
)
||
h
)
;
i
并测试于:
(cat file > outFile) || ( ls -l | grep -i )
(cat file >> outFile) && ls -l | grep -i
((file < file) || ls -l ; ls)
cat < InputFile | tr a-z A-Z | tee out1 > out2 >> out3 | asd aasdasd | asd | asd || asd | asd
a | b || c | d && a || b && d ; g &&
a && b || c > d >> e < f | g
a < b | c | d > e >> f && ((g) || h) ; i
我建议通过将 {-1,0}
传递给 sregex_token_iterator
来收集不匹配和匹配的子字符串,并使用更简单的正则表达式,如 &&|\|\||[;()]
,同时丢弃空的子字符串(这是由于找到连续匹配项时字符串的拆分方式所致):
std::regex rx(R"(&&|\|\||[();])");
std::string exp = "a < b | c | d > e >> f && ((g) || h) ; i";
std::sregex_token_iterator srti(exp.begin(), exp.end(), rx, {-1, 0});
std::vector<std::string> tokens;
std::remove_copy_if(srti, std::sregex_token_iterator(),
std::back_inserter(tokens),
[](std::string const &s) { return s.empty(); });
for( auto & p : tokens ) std::cout <<"'"<< p <<"'"<< std::endl;
见C++ demo,输出:
'a < b | c | d > e >> f '
'&&'
' '
'('
'('
'g'
')'
' '
'||'
' h'
')'
' '
';'
' i'
空字符串删除代码的特别功劳归于