在 C++ 项目中使用 pcre2
Using pcre2 in a c++ project
我正在考虑在我的简单 C++ 应用程序中使用 pcre2(我正在使用 vs2015)。
(我正在查看各种正则表达式库,总的感觉是 pcre/pcre2 是最灵活的)
首先我从官方下载了 pcre2,(http://sourceforge.net/projects/pcre/files/pcre2/10.20/) 并创建了一个非常简单的例子。
#define PCRE2_CODE_UNIT_WIDTH 8
#include <pcre2.h>
...
PCRE2_SPTR subject = (PCRE2_SPTR)std::string("this is it").c_str();
PCRE2_SPTR pattern = (PCRE2_SPTR)std::string("([a-z]+)|\s").c_str();
...
int errorcode;
PCRE2_SIZE erroroffset;
pcre2_code *re = pcre2_compile(pattern, PCRE2_ZERO_TERMINATED,
PCRE2_ANCHORED | PCRE2_UTF, &errorcode,
&erroroffset, NULL);
...
首先文件“pcre2.h”不存在,所以我重命名为pcre2.h.generic到pcre2.h
但后来我遇到了未解析外部的链接器错误。
我猜我需要将源文件中的一个或多个文件包含到项目中。
但是我不愿意在不知道它的作用的情况下随意添加文件。
有人可以提供一些简单的步骤来使用 pcre2 成功构建项目吗?
更新
这不是导入库问题,pcre2.h 没有库,(我在他们的发布位置看不到)。
如果有人想使用 visual studio
构建库
- 从网站下载 pcre2,(http://www.pcre.org/)
- 在 Visual Studio 2015 年(可能还有其他人),创建一个空项目 "Win32 project" 并将其命名为 pcre2。
- 将 \pcre2\src\ 中的所有文件复制到您新创建的空项目中。
- 添加 "NON-AUTOTOOLS-BUILD" 中列出的所有文件(位于基本文件夹中)
- pcre2_auto_possess.c
- pcre2_chartables.c
- pcre2_compile.c
- pcre2_config.c
- 等...
- 将文件 config.h.generic 重命名为 config.h
- 将 config.h 文件添加到项目中。
- 在你的项目中,select 所有 *.c 文件 Go Properties > C/C++ > Precompiled Header > "Not Using Precompiled header"
- Select 项目,转到 Properties > Preprocessor > Preprocessor Definition 和 select 下拉列表,然后添加...
- PCRE2_CODE_UNIT_WIDTH=8
- HAVE_CONFIG_H
编译,应该可以正常创建 lib 文件。
PCRE2_SPTR pattern = (PCRE2_SPTR)std::string("([a-z]+)|\s").c_str();
将此指针与任何 PCRE 函数一起使用将导致未定义的行为。 std::string
临时对象在 pattern
定义的末尾被销毁,导致 pattern
悬空。
我的建议是将 pattern
的类型更改为 std::string
并在将参数传递给 PCRE 函数时调用 c_str()
。它在 C++11 中是一个非常快速的操作(并且您没有使用旧的 GCC 4 ABI)。
还有一些 PCRE 的 C++ 包装器可以帮助您避免此类问题并使 PCRE 更易于使用,但我不支持 Windows 状态。
如果你不介意使用包装器,这是我的:JPCRE2
您需要根据字符串类select基本字符类型(char
、wchar_t
、char16_t
、char32_t
) ] 你将使用(分别为std::string
、std::wstring
、std::u16string
、std::u32string
):
typedef jpcre2::select<char> jp;
//Selecting char as the basic character type will require
//8 bit PCRE2 library where char is 8 bit,
//or 16 bit PCRE2 library where char is 16 bit,
//or 32 bit PCRE2 library where char is 32 bit.
//If char is not 8, 16 or 32 bit, it's a compile error.
匹配示例:
检查字符串是否匹配模式:
if(jp::Regex("(\d)|(\w)").match("I am the subject"))
std::cout<<"\nmatched";
else
std::cout<<"\nno match";
全部匹配并获得匹配数:
size_t count =
jp::Regex("(\d)|(\w)","mi").match("I am the subject", "g");
// 'm' modifier enables multi-line mode for the regex
// 'i' modifier makes the regex case insensitive
// 'g' modifier enables global matching
获取编号 substrings/captured 个组:
jp::VecNum vec_num;
count =
jp::Regex("(\w+)\s*(\d+)","im").initMatch()
.setSubject("I am 23, I am digits 10")
.setModifier("g")
.setNumberedSubstringVector(&vec_num)
.match();
std::cout<<"\nTotal match of first match: "<<vec_num[0][0];
std::cout<<"\nCaptrued group 1 of first match: "<<vec_num[0][1];
std::cout<<"\nCaptrued group 2 of first match: "<<vec_num[0][2];
std::cout<<"\nTotal match of second match: "<<vec_num[1][0];
std::cout<<"\nCaptrued group 1 of second match: "<<vec_num[1][1];
std::cout<<"\nCaptrued group 2 of second match: "<<vec_num[1][2];
命名 substrings/captured 个群组:
jp::VecNas vec_nas;
count =
jp::Regex("(?<word>\w+)\s*(?<digit>\d+)","m")
.initMatch()
.setSubject("I am 23, I am digits 10")
.setModifier("g")
.setNamedSubstringVector(&vec_nas)
.match();
std::cout<<"\nCaptured group (word) of first match: "<<vec_nas[0]["word"];
std::cout<<"\nCaptured group (digit) of first match: "<<vec_nas[0]["digit"];
std::cout<<"\nCaptured group (word) of second match: "<<vec_nas[1]["word"];
std::cout<<"\nCaptured group (digit) of second match: "<<vec_nas[1]["digit"];
遍历所有匹配项和子字符串:
//Iterating through numbered substring
for(size_t i=0;i<vec_num.size();++i){
//i=0 is the first match found, i=1 is the second and so forth
for(size_t j=0;j<vec_num[i].size();++j){
//j=0 is the capture group 0 i.e the total match
//j=1 is the capture group 1 and so forth.
std::cout<<"\n\t("<<j<<"): "<<vec_num[i][j]<<"\n";
}
}
Replace/Substitute 示例:
std::cout<<"\n"<<
///replace all occurrences of a digit with @
jp::Regex("\d").replace("I am the subject string 44", "@", "g");
///swap two parts of a string
std::cout<<"\n"<<
jp::Regex("^([^\t]+)\t([^\t]+)$")
.initReplace()
.setSubject("I am the subject\tTo be swapped according to tab")
.setReplaceWith(" ")
.replace();
替换为匹配评估器:
jp::String callback1(const jp::NumSub& m, void*, void*){
return "("+m[0]+")"; //m[0] is capture group 0, i.e total match (in each match)
}
int main(){
jp::Regex re("(?<total>\w+)", "n");
jp::RegexReplace rr(&re);
String s3 = "I am ঋ আা a string 879879 fdsjkll ১ ২ ৩ ৪ অ আ ক খ গ ঘ আমার সোনার বাংলা";
rr.setSubject(s3)
.setPcre2Option(PCRE2_SUBSTITUTE_GLOBAL);
std::cout<<"\n\n### 1\n"<<
rr.nreplace(jp::MatchEvaluator(callback1));
//nreplace() treats the returned string from the callback as literal,
//while replace() will process the returned string
//with pcre2_substitute()
#if __cplusplus >= 201103L
//example with lambda
std::cout<<"\n\n### Lambda\n"<<
rr.nreplace(
jp::MatchEvaluator(
[](const jp::NumSub& m1, const jp::MapNas& m2, void*){
return "("+m1[0]+"/"+m2.at("total")+")";
}
));
#endif
return 0;
}
您可以阅读完整的文档 here。
我不知道这是否仍然是您正在查看的内容...但以防万一这有帮助吗?
来自 pcre2api 手册页:
在Windows环境中,如果要针对非dll PCRE2库静态link应用程序,必须在包含pcre2.h之前定义PCRE2_STATIC .
您可以按照以下步骤操作:
- 下载并安装cmake。
- 设置源文件夹位置和 VS 项目文件夹。
- 点击配置并select你的 VS 版本。
- 配置过程完成后,您可以select列表中的 8、16 和/或 32 位。
- 按生成,然后打开项目文件夹中的VS解决方案文件。这将在 VS 中打开解决方案。
- 大约有 6 个项目。突出显示 pcre2._ 项目。转到首选项并确保输出文件用于 DLL。对 pcre2posix 项目重复此步骤。然后将 greptest 设置为构建为 exe(可执行文件),将另一个设置为可执行文件。
- 此时您可以尝试全部构建,但您可能需要先构建 DLL,因为可执行文件依赖于它们(或者更确切地说是它们的静态库)进行链接。
- 成功构建所有 6 个项目后,您应该在调试或发布文件夹中拥有共享/静态库和测试程序。
这里有关于查尔斯·托马斯回答的更多细节...
如果您在 Windows 上使用 C++ 并且将 PCRE2 构建为静态库...在 pcre2.h 中,有这个...
#if defined(_WIN32) && !defined(PCRE2_STATIC)
# ifndef PCRE2_EXP_DECL
# define PCRE2_EXP_DECL extern __declspec(dllimport)
# endif
#endif
_WIN32 被定义是因为你在Windows,但是你需要在pcre2.h 的顶部定义PCRE2_STATIC,像这样...
#define PCRE2_STATIC 1
这使得它把 extern "C" 放在每个函数前面,而不是 extern __declspec(dllimport)所以你可以 link 静态。
我正在考虑在我的简单 C++ 应用程序中使用 pcre2(我正在使用 vs2015)。 (我正在查看各种正则表达式库,总的感觉是 pcre/pcre2 是最灵活的)
首先我从官方下载了 pcre2,(http://sourceforge.net/projects/pcre/files/pcre2/10.20/) 并创建了一个非常简单的例子。
#define PCRE2_CODE_UNIT_WIDTH 8
#include <pcre2.h>
...
PCRE2_SPTR subject = (PCRE2_SPTR)std::string("this is it").c_str();
PCRE2_SPTR pattern = (PCRE2_SPTR)std::string("([a-z]+)|\s").c_str();
...
int errorcode;
PCRE2_SIZE erroroffset;
pcre2_code *re = pcre2_compile(pattern, PCRE2_ZERO_TERMINATED,
PCRE2_ANCHORED | PCRE2_UTF, &errorcode,
&erroroffset, NULL);
...
首先文件“pcre2.h”不存在,所以我重命名为pcre2.h.generic到pcre2.h
但后来我遇到了未解析外部的链接器错误。
我猜我需要将源文件中的一个或多个文件包含到项目中。 但是我不愿意在不知道它的作用的情况下随意添加文件。
有人可以提供一些简单的步骤来使用 pcre2 成功构建项目吗?
更新
这不是导入库问题,pcre2.h 没有库,(我在他们的发布位置看不到)。
如果有人想使用 visual studio
构建库- 从网站下载 pcre2,(http://www.pcre.org/)
- 在 Visual Studio 2015 年(可能还有其他人),创建一个空项目 "Win32 project" 并将其命名为 pcre2。
- 将 \pcre2\src\ 中的所有文件复制到您新创建的空项目中。
- 添加 "NON-AUTOTOOLS-BUILD" 中列出的所有文件(位于基本文件夹中)
- pcre2_auto_possess.c
- pcre2_chartables.c
- pcre2_compile.c
- pcre2_config.c
- 等...
- 将文件 config.h.generic 重命名为 config.h
- 将 config.h 文件添加到项目中。
- 在你的项目中,select 所有 *.c 文件 Go Properties > C/C++ > Precompiled Header > "Not Using Precompiled header"
- Select 项目,转到 Properties > Preprocessor > Preprocessor Definition 和 select 下拉列表,然后添加...
- PCRE2_CODE_UNIT_WIDTH=8
- HAVE_CONFIG_H
编译,应该可以正常创建 lib 文件。
PCRE2_SPTR pattern = (PCRE2_SPTR)std::string("([a-z]+)|\s").c_str();
将此指针与任何 PCRE 函数一起使用将导致未定义的行为。 std::string
临时对象在 pattern
定义的末尾被销毁,导致 pattern
悬空。
我的建议是将 pattern
的类型更改为 std::string
并在将参数传递给 PCRE 函数时调用 c_str()
。它在 C++11 中是一个非常快速的操作(并且您没有使用旧的 GCC 4 ABI)。
还有一些 PCRE 的 C++ 包装器可以帮助您避免此类问题并使 PCRE 更易于使用,但我不支持 Windows 状态。
如果你不介意使用包装器,这是我的:JPCRE2
您需要根据字符串类select基本字符类型(char
、wchar_t
、char16_t
、char32_t
) ] 你将使用(分别为std::string
、std::wstring
、std::u16string
、std::u32string
):
typedef jpcre2::select<char> jp;
//Selecting char as the basic character type will require
//8 bit PCRE2 library where char is 8 bit,
//or 16 bit PCRE2 library where char is 16 bit,
//or 32 bit PCRE2 library where char is 32 bit.
//If char is not 8, 16 or 32 bit, it's a compile error.
匹配示例:
检查字符串是否匹配模式:
if(jp::Regex("(\d)|(\w)").match("I am the subject"))
std::cout<<"\nmatched";
else
std::cout<<"\nno match";
全部匹配并获得匹配数:
size_t count =
jp::Regex("(\d)|(\w)","mi").match("I am the subject", "g");
// 'm' modifier enables multi-line mode for the regex
// 'i' modifier makes the regex case insensitive
// 'g' modifier enables global matching
获取编号 substrings/captured 个组:
jp::VecNum vec_num;
count =
jp::Regex("(\w+)\s*(\d+)","im").initMatch()
.setSubject("I am 23, I am digits 10")
.setModifier("g")
.setNumberedSubstringVector(&vec_num)
.match();
std::cout<<"\nTotal match of first match: "<<vec_num[0][0];
std::cout<<"\nCaptrued group 1 of first match: "<<vec_num[0][1];
std::cout<<"\nCaptrued group 2 of first match: "<<vec_num[0][2];
std::cout<<"\nTotal match of second match: "<<vec_num[1][0];
std::cout<<"\nCaptrued group 1 of second match: "<<vec_num[1][1];
std::cout<<"\nCaptrued group 2 of second match: "<<vec_num[1][2];
命名 substrings/captured 个群组:
jp::VecNas vec_nas;
count =
jp::Regex("(?<word>\w+)\s*(?<digit>\d+)","m")
.initMatch()
.setSubject("I am 23, I am digits 10")
.setModifier("g")
.setNamedSubstringVector(&vec_nas)
.match();
std::cout<<"\nCaptured group (word) of first match: "<<vec_nas[0]["word"];
std::cout<<"\nCaptured group (digit) of first match: "<<vec_nas[0]["digit"];
std::cout<<"\nCaptured group (word) of second match: "<<vec_nas[1]["word"];
std::cout<<"\nCaptured group (digit) of second match: "<<vec_nas[1]["digit"];
遍历所有匹配项和子字符串:
//Iterating through numbered substring
for(size_t i=0;i<vec_num.size();++i){
//i=0 is the first match found, i=1 is the second and so forth
for(size_t j=0;j<vec_num[i].size();++j){
//j=0 is the capture group 0 i.e the total match
//j=1 is the capture group 1 and so forth.
std::cout<<"\n\t("<<j<<"): "<<vec_num[i][j]<<"\n";
}
}
Replace/Substitute 示例:
std::cout<<"\n"<<
///replace all occurrences of a digit with @
jp::Regex("\d").replace("I am the subject string 44", "@", "g");
///swap two parts of a string
std::cout<<"\n"<<
jp::Regex("^([^\t]+)\t([^\t]+)$")
.initReplace()
.setSubject("I am the subject\tTo be swapped according to tab")
.setReplaceWith(" ")
.replace();
替换为匹配评估器:
jp::String callback1(const jp::NumSub& m, void*, void*){
return "("+m[0]+")"; //m[0] is capture group 0, i.e total match (in each match)
}
int main(){
jp::Regex re("(?<total>\w+)", "n");
jp::RegexReplace rr(&re);
String s3 = "I am ঋ আা a string 879879 fdsjkll ১ ২ ৩ ৪ অ আ ক খ গ ঘ আমার সোনার বাংলা";
rr.setSubject(s3)
.setPcre2Option(PCRE2_SUBSTITUTE_GLOBAL);
std::cout<<"\n\n### 1\n"<<
rr.nreplace(jp::MatchEvaluator(callback1));
//nreplace() treats the returned string from the callback as literal,
//while replace() will process the returned string
//with pcre2_substitute()
#if __cplusplus >= 201103L
//example with lambda
std::cout<<"\n\n### Lambda\n"<<
rr.nreplace(
jp::MatchEvaluator(
[](const jp::NumSub& m1, const jp::MapNas& m2, void*){
return "("+m1[0]+"/"+m2.at("total")+")";
}
));
#endif
return 0;
}
您可以阅读完整的文档 here。
我不知道这是否仍然是您正在查看的内容...但以防万一这有帮助吗?
来自 pcre2api 手册页:
在Windows环境中,如果要针对非dll PCRE2库静态link应用程序,必须在包含pcre2.h之前定义PCRE2_STATIC .
您可以按照以下步骤操作:
- 下载并安装cmake。
- 设置源文件夹位置和 VS 项目文件夹。
- 点击配置并select你的 VS 版本。
- 配置过程完成后,您可以select列表中的 8、16 和/或 32 位。
- 按生成,然后打开项目文件夹中的VS解决方案文件。这将在 VS 中打开解决方案。
- 大约有 6 个项目。突出显示 pcre2._ 项目。转到首选项并确保输出文件用于 DLL。对 pcre2posix 项目重复此步骤。然后将 greptest 设置为构建为 exe(可执行文件),将另一个设置为可执行文件。
- 此时您可以尝试全部构建,但您可能需要先构建 DLL,因为可执行文件依赖于它们(或者更确切地说是它们的静态库)进行链接。
- 成功构建所有 6 个项目后,您应该在调试或发布文件夹中拥有共享/静态库和测试程序。
这里有关于查尔斯·托马斯回答的更多细节...
如果您在 Windows 上使用 C++ 并且将 PCRE2 构建为静态库...在 pcre2.h 中,有这个...
#if defined(_WIN32) && !defined(PCRE2_STATIC)
# ifndef PCRE2_EXP_DECL
# define PCRE2_EXP_DECL extern __declspec(dllimport)
# endif
#endif
_WIN32 被定义是因为你在Windows,但是你需要在pcre2.h 的顶部定义PCRE2_STATIC,像这样...
#define PCRE2_STATIC 1
这使得它把 extern "C" 放在每个函数前面,而不是 extern __declspec(dllimport)所以你可以 link 静态。