正则表达式使用

本文主要讲解了一些不太常用的正则表达式语法,并给出了一些自己写的(或找的)常见的一些正则表达式用于校验或是内容的提取,可能存在一些错误,最后给出了c语言、python、java如何使用正则表达式的语法。

一些正则表达式语法

符号描述
^匹配输入字符串的开始位置,除非在方括号表达式中使用,此时它表示不接受该字符集合。要匹配 ^ 字符本身,请使用 ^。
$匹配输入字符串的结尾位置。如果设置了 RegExp 对象的 Multiline 属性,则 $ 也匹配 ‘\n’ 或 ‘\r’。要匹配 $ 字符本身,请使用 \$。
匹配前面的子表达式零次或一次。例如,“do(es)?” 可以匹配 “do” 或 “does” 。? 等价于 {0,1}。
当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串 “oooo”,‘o+?’ 将匹配单个 “o”,而 ‘o+’ 将匹配所有 ‘o’。
(?=pattern)正向肯定预查(look ahead positive assert),在任何匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,“Windows(?=95|98|NT|2000)“能匹配"Windows2000"中的"Windows”,但不能匹配"Windows3.1"中的"Windows”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。
(?!pattern)正向否定预查(negative assert),在任何不匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如"Windows(?!95|98|NT|2000)“能匹配"Windows3.1"中的"Windows”,但不能匹配"Windows2000"中的"Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。
(?<=pattern)反向(look behind)肯定预查,与正向肯定预查类似,只是方向相反。例如,"(?<=95|98|NT|2000)Windows"能匹配"2000Windows"中的"Windows",但不能匹配"3.1Windows"中的"Windows"。
(?<!pattern)反向否定预查,与正向否定预查类似,只是方向相反。例如"(?|98|NT|2000)Windows"能匹配"3.1Windows"中的"Windows",但不能匹配"2000Windows"中的"Windows"。
\b匹配一个单词边界,也就是指单词和空格间的位置。例如, ‘er\b’ 可以匹配"never" 中的 ‘er’,但不能匹配 “verb” 中的 ‘er’。
\B匹配非单词边界。‘er\B’ 能匹配 “verb” 中的 ‘er’,但不能匹配 “never” 中的 ‘er’。
\D匹配一个非数字字符。等价于 [^0-9]。
\d匹配一个数字字符。等价于 [0-9]。
\s匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。
\S匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。
\w匹配字母、数字、下划线。等价于’[A-Za-z0-9_]’。
\W匹配非字母、数字、下划线。等价于 [^A-Za-z0-9_]。
\un匹配 n,其中 n 是一个用四个十六进制数字表示的 Unicode 字符。例如, \u00A9 匹配版权符号 (?)。

常用的正则表达式

  1. 校验密码,要求密码为大小写字母或数字,且位数在8位到10位。

    ^[a-zA-Z0-9]{8,10}$
    
  2. 校验字符串,要求只能维中文。

    ^[\u4e00-\u9fa5]*$
    
  3. 校验字符串,要求只能是字母数字或下划线。

    ^\w+$
    
  4. 校验密码,要求只能是大小写字母或数字,且位数在6到16位,且不能是纯数字或纯字母

    ^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,16}$
    
  5. 校验金额,要求为两位小数。

    ^[0-9]+(\.[0-9]{2})?$
    
  6. 从文本中提取url。

    (f|ht){1}(tp|tps):\/\/([\w-]+\.)+[\w-]+(\/[\w-./?%&=]*)?
    
  7. 提取网页中的图片。

    < *[img][^\\>]*[src] *= *[\"\']{0,1}([^\"\'\\ >]*)
    
  8. 提取网页中的注释。

    <!--(.*?)-->
    

代码书写

c语言

首先介绍一下一些函数接口。

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内部表示结构
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, 输入参数, 用来返回匹配位置偏移量的数组的最大大小
返回值:匹配成功返回非负数,匹配返回负数

接下来举一个例子,判断给定一个字符串是否满足密码要求(只能包含字母和数字,并且位数在6位到16位,并且不能是纯字母或纯数字)。

#include<pcre.h>
#include<stdio.h>
int main(){
        int ovector[10];
        const char* err_ptr = NULL;
        int err_offset = -1;
        char check[] = "^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,16}$";
        pcre* re_check = pcre_compile(check, 0, &err_ptr, &err_offset, NULL);
        if (re_check == NULL){
                printf("error\n");
                return 0;
        }
        int result = pcre_exec(re_check, NULL, "faf1234ci", 9, 0, 0, ovector, 10);
        if(result > 0) {
                printf("match\n");
                printf("%d %d\n", ovector[0], ovector[1]);
        }
        else{
                printf("not match\n");
        }
        result = pcre_exec(re_check, NULL, "12345611", 8, 0, 0, ovector, 10);
        if(result > 0) {
                printf("match\n");
                printf("%d %d\n", ovector[0], ovector[1]);//0和1为匹配串的起始位置和结束位置
        }
        else {
                printf("not match\n");
        }
        pcre_free(re_check);
        return 0;
}
/*
输出为:
match
0 9
not match
*/

python

采用re模块进行正则式的匹配。

re.match函数

re.match 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none。

函数语法

re.match(pattern, string, flags=0)

函数参数说明:

参数描述
pattern匹配的正则表达式
string要匹配的字符串。
flags标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。参见:正则表达式修饰符 - 可选标志

匹配成功re.match方法返回一个匹配的对象,否则返回None。

我们可以使用group(num) 或 groups() 匹配对象函数来获取匹配表达式。

匹配对象方法描述
group(num=0)匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。
groups()返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。

可以用span()函数来获得匹配的位置。

match函数是从文本串开始进行匹配的,不管有没有^。

import re
pattern = "(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,16}$"
print(re.match(pattern, "1234567712a"))
print(re.match(pattern, "1234567712a").span())
print(re.match(pattern, "123"))
#输出:
#<re.Match object; span=(0, 11), match='1234567712a'>
#(0, 11)
#None

re.search函数

re.search 扫描整个字符串并返回第一个成功的匹配。

函数语法:

re.search(pattern, string, flags=0)

函数参数说明:

参数描述
pattern匹配的正则表达式
string要匹配的字符串。
flags标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。

匹配成功re.search方法返回一个匹配的对象,否则返回None。

我们可以使用group(num) 或 groups() 匹配对象函数来获取匹配表达式。

匹配对象方法描述
group(num=0)匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。
groups()返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。
#匹配大小写字母
import re
pattern = re.compile("[a-z]", re.I)
print(re.search(pattern, "a"))
print(re.search(pattern, "12ZZ"))
print(re.search(pattern, "123"))

#输出:<re.Match object; span=(0, 1), match='a'>
#<re.Match object; span=(2, 3), match='Z'>
#None

re.findall函数

在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。

注意: match 和 search 是匹配一次 findall 匹配所有。

语法格式为:

findall(string[, pos[, endpos]])

参数:

  • string : 待匹配的字符串。
  • pos : 可选参数,指定字符串的起始位置,默认为 0。
  • endpos : 可选参数,指定字符串的结束位置,默认为字符串的长度。
import re
pattern = "[a-z]+"
print(re.findall(pattern, "a"))
print(re.findall(pattern, "12zz123j"))
print(re.findall(pattern, "123"))
#输出:['a']
#['zz', 'j']
#[]

re.compile函数

compile 函数用于编译正则表达式,生成一个正则表达式( Pattern )对象,供 match() 和 search() 这两个函数使用。

语法格式为:

re.compile(pattern[, flags])

参数:

  • pattern : 一个字符串形式的正则表达式
  • flags : 可选,表示匹配模式,比如忽略大小写,多行模式等,具体参数为:
    1. re.I 忽略大小写
    2. re.L 表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境
    3. re.M 多行模式
    4. re.S 即为 . 并且包括换行符在内的任意字符(. 不包括换行符)
    5. re.U 表示特殊字符集 \w, \W, \b, \B, \d, \D, \s, \S 依赖于 Unicode 字符属性数据库
    6. re.X 为了增加可读性,忽略空格和 # 后面的注释

java

java.util.regex 包主要包括以下三个类:

  • Pattern 类:

    pattern 对象是一个正则表达式的编译表示。Pattern 类没有公共构造方法。要创建一个 Pattern 对象,你必须首先调用其公共静态编译方法,它返回一个 Pattern 对象。该方法接受一个正则表达式作为它的第一个参数。

  • Matcher 类:

    Matcher 对象是对输入字符串进行解释和匹配操作的引擎。与Pattern 类一样,Matcher 也没有公共构造方法。你需要调用 Pattern 对象的 matcher 方法来获得一个 Matcher 对象。

  • PatternSyntaxException:

    PatternSyntaxException 是一个非强制异常类,它表示一个正则表达式模式中的语法错误。

第一个例子同样是进行密码的校验,采用Pattern.matches函数,返回值为布尔值。

import java.util.regex.*;
public class Test {
	public static void main(String[] args) {
 
      	String pattern = "^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,16}$";
 
      	boolean isMatch = Pattern.matches(pattern, "1234144141");
      	boolean isMatch2 = Pattern.matches(pattern, "1239afc");
      	System.out.println(isMatch+" "+isMatch2);
	}
}
/*结果:
false true
*/

第二个例子采用和python或c类似的compile函数,然后利用matcher函数进行匹配,和python类似,java也含有group函数。如下:

import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
public class Test
{
    public static void main( String args[] ){
 
      // 按指定模式在字符串查找
      String line = "This order was placed for QT3000! OK?";
      String pattern = "(\\D*)(\\d+)(.*)";
 
      // 创建 Pattern 对象
      Pattern r = Pattern.compile(pattern);
 
      // 现在创建 matcher 对象
      Matcher m = r.matcher(line);
      if (m.find( )) {
         System.out.println("Found value: " + m.group(0) );
         System.out.println("Found value: " + m.group(1) );
         System.out.println("Found value: " + m.group(2) );
         System.out.println("Found value: " + m.group(3) ); 
      } else {
         System.out.println("NO MATCH");
      }
   }
}
/*结果:
Found value: This order was placed for QT3000! OK?
Found value: This order was placed for QT
Found value: 3000
Found value: ! OK?
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值