将 C# 正则表达式与 lookbehinds 翻译成 C++
Translate C# regex with lookbehinds to C++
@polygenelubricants 对 this question 的回答包括一个 C# 正则表达式,用于将 PascalCase 字符串拆分为单独的单词,即:
Regex r = new Regex(
@" (?<=[A-Z])(?=[A-Z][a-z]) # UC before me, UC lc after me
| (?<=[^A-Z])(?=[A-Z]) # Not UC before me, UC after me
| (?<=[A-Za-z])(?=[^A-Za-z]) # Letter before me, non letter after me
",
RegexOptions.IgnorePatternWhitespace
);
我想在 C++ 中使用相同的正则表达式。但是,C++ 正则表达式语法不允许 (?<=...)
形式的回顾。无论如何都可以完成这项工作吗?
编辑:这显然不是重复的。我知道 C++ 不支持 lookbehinds,我想问如果没有它们是否可以实现相同的功能。作为参考,以下是使用 Boost 正则表达式执行此操作的方法,它确实支持后视并且我希望避免使用它:
#include <iostream>
#include <boost/algorithm/string/regex.hpp>
#include <boost/regex.hpp>
int main()
{
boost::regex r(
"(?<=[A-Z])(?=[A-Z][a-z])"
"|(?<=[^A-Z])(?=[A-Z])"
"|(?<=[A-Za-z])(?=[^A-Za-z])"
);
std::vector<std::string> input {
"AutomaticTrackingSystem",
"XMLEditor",
"AnXMLAndXSLT2.0Tool"
};
for (auto const &str : input) {
std::vector<std::string> str_split;
boost::algorithm::split_regex(str_split, str, r);
for (auto const &str_ : str_split)
std::cout << str_ << std::endl;
}
}
您可以将正则表达式更改为不使用回顾:[A-Z](?=[A-Z][a-z])|[^A-Z](?=[A-Z])|[A-Za-z](?=[^A-Za-z])
。
最后原来的正则表达式是在寻找新词的开头,所以它不得不在后面寻找前一个词的结尾。但是我们可以寻找一个词的结尾并向前看下一个词的开头。那么我们只需要将位置“移动”+1
.
const std::sregex_iterator End;
// the code doesn't handle correctly "",
// handle as a special case
std::string str = "ThisIsAPascalStringX";
std::regex rx("[A-Z](?=[A-Z][a-z])|[^A-Z](?=[A-Z])|[A-Za-z](?=[^A-Za-z])");
std::vector<std::string> pieces;
size_t lastStartPosition = 0;
for (auto i(std::sregex_iterator(str.begin(), str.end(), rx)); i != End; ++i)
{
size_t startPosition = i->position() + 1;
pieces.push_back(str.substr(lastStartPosition, startPosition - lastStartPosition));
lastStartPosition = startPosition;
}
pieces.push_back(str.substr(lastStartPosition));
std::cout << "<-- start" << std::endl;
for (auto& s : pieces)
{
std::cout << s << std::endl;
}
std::cout << "<-- end" << std::endl;
@polygenelubricants 对 this question 的回答包括一个 C# 正则表达式,用于将 PascalCase 字符串拆分为单独的单词,即:
Regex r = new Regex(
@" (?<=[A-Z])(?=[A-Z][a-z]) # UC before me, UC lc after me
| (?<=[^A-Z])(?=[A-Z]) # Not UC before me, UC after me
| (?<=[A-Za-z])(?=[^A-Za-z]) # Letter before me, non letter after me
",
RegexOptions.IgnorePatternWhitespace
);
我想在 C++ 中使用相同的正则表达式。但是,C++ 正则表达式语法不允许 (?<=...)
形式的回顾。无论如何都可以完成这项工作吗?
编辑:这显然不是重复的。我知道 C++ 不支持 lookbehinds,我想问如果没有它们是否可以实现相同的功能。作为参考,以下是使用 Boost 正则表达式执行此操作的方法,它确实支持后视并且我希望避免使用它:
#include <iostream>
#include <boost/algorithm/string/regex.hpp>
#include <boost/regex.hpp>
int main()
{
boost::regex r(
"(?<=[A-Z])(?=[A-Z][a-z])"
"|(?<=[^A-Z])(?=[A-Z])"
"|(?<=[A-Za-z])(?=[^A-Za-z])"
);
std::vector<std::string> input {
"AutomaticTrackingSystem",
"XMLEditor",
"AnXMLAndXSLT2.0Tool"
};
for (auto const &str : input) {
std::vector<std::string> str_split;
boost::algorithm::split_regex(str_split, str, r);
for (auto const &str_ : str_split)
std::cout << str_ << std::endl;
}
}
您可以将正则表达式更改为不使用回顾:[A-Z](?=[A-Z][a-z])|[^A-Z](?=[A-Z])|[A-Za-z](?=[^A-Za-z])
。
最后原来的正则表达式是在寻找新词的开头,所以它不得不在后面寻找前一个词的结尾。但是我们可以寻找一个词的结尾并向前看下一个词的开头。那么我们只需要将位置“移动”+1
.
const std::sregex_iterator End;
// the code doesn't handle correctly "",
// handle as a special case
std::string str = "ThisIsAPascalStringX";
std::regex rx("[A-Z](?=[A-Z][a-z])|[^A-Z](?=[A-Z])|[A-Za-z](?=[^A-Za-z])");
std::vector<std::string> pieces;
size_t lastStartPosition = 0;
for (auto i(std::sregex_iterator(str.begin(), str.end(), rx)); i != End; ++i)
{
size_t startPosition = i->position() + 1;
pieces.push_back(str.substr(lastStartPosition, startPosition - lastStartPosition));
lastStartPosition = startPosition;
}
pieces.push_back(str.substr(lastStartPosition));
std::cout << "<-- start" << std::endl;
for (auto& s : pieces)
{
std::cout << s << std::endl;
}
std::cout << "<-- end" << std::endl;