C中调用pcre正则库

分类: C/C++

在Linux的C标准库中包含了一个正则库(Windows下无此正则库),只需要引用<regex.h>即可使用,但是使用了几天却发现Linux自带的正则库无法使用元字符和非贪婪匹配,例如:

str:   1.1.1.1

regex: (\d*.\d*.\d*.\d*)

其中的正则表达式使用了元字符\d来匹配数字,但在regex.h的正则库中却无法匹配。

str:   \<br\>123\<br\>456\<br\>

regex:

\<br\>(.+?)\<br\>

其中的正则表达式使用了非贪婪匹配,但在regex.h的正则库中却只匹配到了“123\<br\>456”。

最后查了下pcre正则库的使用方法,照着网上的例子写了段测试代码:

/* Compile thuswise:

*

*   gcc -Wall pcre1.c -I/usr/local/include -L/usr/local/lib -R/usr/local/lib -lpcre

*

*/

#include <stdio.h>

#include <string.h>

#include <pcre.h>

#define OVECCOUNT 30/* should be a multiple of 3 */

#define EBUFLEN 128

#define BUFLEN 1024

int main()

{

pcre *re;

const char *error;

int  erroffset;

int  ovector[OVECCOUNT];

int  rc, i;

char src[] = "123.123.123.123:80|1.1.1.1:88";

char pattern[] = "(\\d*.\\d*.\\d*.\\d*):(\\d*)";

printf("String : %s\n", src);

printf("Pattern: \"%s\"\n", pattern);

re = pcre_compile(pattern, 0, &error, &erroffset, NULL);

if (re == NULL) {

printf("PCRE compilation failed at offset %d: %s\n", erroffset, error);

return 1;

}

char *p = src;

while ( ( rc = pcre_exec(re, NULL, p, strlen(p), 0, 0, ovector, OVECCOUNT)) != PCRE_ERROR_NOMATCH )

{

printf("\nOK, has matched ...\n\n");

for (i = 0; i < rc; i++)

{

char *substring_start = p + ovector[2*i];

int substring_length = ovector[2*i+1] - ovector[2*i];

char matched[1024];

memset( matched, 0, 1024 );

strncpy( matched, substring_start, substring_length );

printf( "match:%s\n", matched );

}

p += ovector[1];

if ( !p )

{

break;

}

}

pcre_free(re);

return 0;

}

以上代码的打印结果如下:

String : 123.123.123.123:80|1.1.1.1:88

Pattern: "(\d*.\d*.\d*.\d*):(\d*)"

OK, has matched ...

0: 123.123.123.123:80

1: 123.123.123.123

2: 80

OK, has matched ...

0: 1.1.1.1:88

1: 1.1.1.1

2: 88

以上代码主要用到了pcre_compile和pcre_exec两个函数,其原型如下:

(1). pcre_compile

1 2 3 4 5 6 7 8 9 10 pcre *pcre_compile(const char *pattern, int options, const char **errptr, int *erroffset, const unsigned char *tableptr); 功能:编译指定的正则表达式 参数:pattern, 输入参数,将要被编译的字符串形式的正则表达式 options, 输入参数,用来指定编译时的一些选项 errptr, 输出参数,用来输出错误信息 erroffset, 输出参数,pattern中出错位置的偏移量 tableptr, 输入参数,用来指定字符表,一般情况用NULL, 使用缺省的字符表 返回值:被编译好的正则表达式的pcre内部表示结构

(2). pcre_exec

1 2 3 4 5 6 7 8 9 10 11 12 13
int pcre_exec(const pcre *code, const pcre_extra *extra, const char *subject, int length, int startoffset, int options, int *ovector, int ovecsize);

功能:用来检查某个字符串是否与指定的正则表达式匹配 参数: code, 输入参数,用pcre_compile编译好的正则表达结构的指针 extra, 输入参数,用来向pcre_exec传一些额外的数据信息的结构的指针 subject, 输入参数,要被用来匹配的字符串 length, 输入参数, 要被用来匹配的字符串的长度 startoffset, 输入参数,用来指定subject从什么位置开始被匹配的偏移量 options, 输入参数, 用来指定匹配过程中的一些选项 ovector, 输出参数,用来返回匹配位置偏移量的数组 ovecsize, 输入参数, 用来返回匹配位置偏移量的数组的最大大小 返回值:匹配成功返回非负数,匹配返回负数

其中ovector这个参数需要明白,如果pcre成功匹配的话,则会把匹配字符串的起止位置写入ovector中,例如以上代码中ovector的值如下:

$1 = {0, 18, 0, 15, 16, 18, 134513344, 134513569, 671417176, 671662336, 671589112, -1077941576, 671417750, 671662336, 671589112, -1077941512, 671405544, 671632420, 1,

-1077941528, 1, 0, 0, 1, 0, 0, 0, 673030784, 16, 0}

由于代码在预定义中设置最多匹配的数量为30个,所以这里列出了30个值,其实pcre_exec只匹配到了3个结果,变量rc保存的就是pcre_exec的匹配数量。那么这三个匹配结果的起止位置分别是:

0,18 = 123.123.123.123:80

0,15 = 123.123.123.123

16,18 = 80

由此可见,根据ovector中的值就可以提取出匹配结果。

另 外,代码中的正则表达式“(\d*.\d*.\d*.\d*):(\d*)”用到了两个小括号,由于正则表达式会将一对小括号中匹配到的值保存到匹配结果 中,所以这段正则表达式匹配到了三个结果,如果目的只是匹配IP地址和端口号的话,则可以去掉小括号,即“\d*.\d*.\d*.\d*:\d*”,这 样就只会匹配到一个结果。

参考资料:

http://www.wuzesheng.com/?p=994

http://hi.baidu.com/ajoe/blog/item/83dd800a7178e335b0351d6c.html

http://hi.baidu.com/joec3/blog/item/5375d3da14ab07d6b7fd487b.html/cmtid/79872dc323e4935bb219a8f2

时间: 2024-09-29 18:16:46

C中调用pcre正则库的相关文章

JNI_Android项目中调用.so动态库

JNI_Android项目中调用.so动态库 2014年6月3日 JNI学习 参考:http://blog.sina.com.cn/s/blog_4298002e01013zk8.html 上一篇笔者介绍了如何使用Java代码调用DLL动态库中的C/C++方法,似乎已经是很久以前的做法了,遇到的错误笔者还未找到解决方案,但动态库着实是找到的,只是无法调用相应的方法.本篇博客来介绍一下如何在Android项目当中使用NDK生成.so动态链接库,并在程序中使用. 1. 在Eclipse中创建项目:T

使用ctypes在Python中调用C++动态库

使用ctypes在Python中调用C++动态库 入门操作 使用ctypes库可以直接调用C语言编写的动态库,而如果是调用C++编写的动态库,需要使用extern关键字对动态库的函数进行声明: #include <iostream> using namespace std; extern "C" { void greet() { cout << "hello python" << endl; } } 将上述的C++程序编译成动态链

JNI_Android项目中调用.so动态库实现详解

转自:http://www.yxkfw.com/?p=7223 1. 在Eclipse中创建项目:TestJNI 2. 新创建一个class:TestJNI.java package com.wwj.jni; public class TestJNI { public native boolean Init(); public native int Add(int x, int y); public native void Destory(); } 以上代码声明三个本地方法. 3. 编译JNI

JNI_Android 项目中调用.so动态库实现详解

转自:http://www.yxkfw.com/?p=7223 1. 在Eclipse中创建项目:TestJNI 2. 新创建一个class:TestJNI.java package com.wwj.jni; public class TestJNI { public native boolean Init(); public native int Add(int x, int y); public native void Destory(); } 以上代码声明三个本地方法. 3. 编译JNI

JNI_Android项目中调用.so动态库实现详解【转】

转自 http://www.cnblogs.com/sevenyuan/p/4202759.html 1. 在Eclipse中创建项目:TestJNI 2. 新创建一个class:TestJNI.java package com.wwj.jni; public class TestJNI { public native boolean Init(); public native int Add(int x, int y); public native void Destory(); } 以上代码

星云链智能合约开发(八):智能合约中调用内置库

BigNumber BigNumber 模块构建于 bignumber.js之上,用来处理任意精度的十进制和非十进制运算.合约可以直接使用 BigNumber 来处理交易和其他转账操作中涉及到的数值计算. var value = new BigNumber(0); value.plus(1); - Storage storage 模块用来支持Nebulas上的数据持久化存储.功能上类似于传统的键值存储系统,当然存储不是免费的,需要消耗一定的 GAS.LocalContractStorage 是可

C#中调用user32.dll库的keybd_Event函数,操作键盘

keybd_event()的函数原型是: void keybd_event( byte bVk,          //虚拟键码 byte bScan,       //该键的硬件扫描码 dword dwFlags   //函数操作的各个方面的一个标志位集 dword dwExtraInfo  //与击键相关的附加的32位值 ); 其中第三个参数有三种取值: · 0:按下 · 1:扩展键 · 2:弹起 keybd_event(0x41, 0x1e, 0x0000, 0); // 按下 a key

Swift项目中调用Objective-C的库

这是来自stack overflow上的一个回答,更多回答请查看: http://stackoverflow.com/questions/24002369/how-to-call-objective-c-code-from-swift Using Objective-C Classes in Swift * If you have an existing class that you'd like to use, perform Step 2 and then skip to Step 5. (

C#中调用C++动态库的函数

[System.Runtime.InteropServices.DllImport("DebugToolWin",CallingConvention=CallingConvention.Cdecl)] //该语句是引入非托管代码程序集 public static extern bool DebugOutStr(string strValue); [System.Runtime.InteropServices.DllImport("DebugToolWin",Call