常见的正则表达式及其应用

正则表达式是一种文本模式,包括普通字符和特殊字符。
正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串。

使用正则表达式可以:

基本语法

元字符

常用的元字符有.\w\s\d\b^$*+?等。

限定符

限定符用来指定正则表达式的一个给定组件必须要出现多少次才能满足匹配。有 *+?{n}{n,}{n,m} 共6种。

定位符

定位符使您能够将正则表达式固定到行首或行尾。

^$ 分别指字符串的开始与结束,\b 描述单词的前或后边界,\B 表示非单词边界。

反向引用

正则表达式模式或部分模式两边添加圆括号将导致相关匹配存储到一个临时缓冲区中,所捕获的每个子匹配都按照在正则表达式模式中从左到右出现的顺序存储。

每个缓冲区都可以使用 \n 访问。

// 查找重复的单词
var str = "Is is the cost of of gasoline going up up";
// [a-z]+ 指定的,包括一个或多个字母。
// 单词的第二个匹配项是对以前捕获的子匹配项的引用,正好由括号表达式匹配。\1 指定第一个子匹配项。
// i 标记指定不区分大小写。
// 全局标记 g 指定将该表达式应用到输入字符串中能够查找到的尽可能多的匹配。
var patt1 = /\b([a-z]+) \1\b/ig;
document.write(str.match(patt1));
// Is is,of of,up up
// 截取URL中的信息
var str = "http://www.runoob.com:80/html/html-tutorial.html";
// 第一个括号子表达式匹配在冒号和两个正斜杠前面的任何单词。
// 第二个括号子表达式匹配 : 和 / 之后的一个或多个字符。
// 第三个括号子表达式匹配冒号后面的零个或多个数字。只能重复一次该子表达式。
// 第四个括号子表达式匹配不包括 # 或空格字符的任何字符序列。
var patt1 = /(\w+):\/\/([^/:]+)(:\d*)?([^# ]*)/;
arr = str.match(patt1);
for (var i = 0; i < arr.length ; i++) {
    document.write(arr[i]);
    document.write("<br>");
}

// http://www.runoob.com:80/html/html-tutorial.html
// http
// www.runoob.com
// :80
// /html/html-tutorial.html

运算符优先级

正则表达式从左到右进行计算,并遵循优先级顺序。
相同优先级的从左到右进行运算,不同优先级的运算先高后低。

优先级顺序:

  1. 转义符(\
  2. 圆括号和方括号((), (?:), (?=), []
  3. 限定符(*, +, ?, {n}, {n,}, {n,m}
  4. 位置和顺序(^, $, \任何元字符、任何字符
  5. “或”操作(|

快速检索表

正则表达式修饰符

正则表达式可以包含一些可选标志修饰符来控制匹配的模式。

修饰符 描述
re.I 使匹配对大小写不敏感
re.L 做本地化识别(locale-aware)匹配
re.M 多行匹配,影响 ^ 和 $
re.S 使 . 匹配包括换行在内的所有字符
re.U 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B.
re.X 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。

正则表达式模式

正则表达式通常都包含反斜杠,所以尽量使用原始字符串来表示它们(如r'\t'等价于\\t)。

模式 描述
^ 匹配字符串的开头。
$ 匹配字符串的末尾。
() 标记一个子表达式的开始和结束位置,子表达式可以使用下标索引取值。
. 匹配任意字符,除了换行符。
当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符。
* 匹配0个或多个的字符串。
+ 匹配1个或多个的字符串。
? 匹配0个或1个的字符串。
*?,+?,?? 非贪婪模式, 只匹配符合条件的最少字符。
[…] 用来表示一组字符。
[^…] 不在[]中的字符。
{n} n 是一个非负整数,匹配确定的 n 次。
例如,”o{2}” 可以匹配 “food” 中的两个 o。
{n,} n 是一个非负整数,至少匹配 n 次。
{n,m} m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。
例如,”o{1,3}” 将匹配 “fooooood” 中的前三个 o。
a| b 匹配a或b。
(?P<name>…) 定义符合条件的子串为某变量,可以在group对象中调用。
(?=pattern) 正向肯定预查(look ahead positive assert),表示被匹配字符后必须有”pattern”
例如,”Windows(?=95|98|NT|2000)”能匹配”Windows2000”中的”Windows”。
(?!pattern) 正向否定预查(negative assert),表示被匹配字符后不能有”pattern”。
(?<=pattern) 反向肯定预查(look behind),表示被匹配的字符前必须有”pattern”。
例如,”(?=95|98|NT|2000)Windows”能匹配”2000Windows”中的”Windows”。
(?<!pattern) 反向否定预查(negative look behind)。
\A 匹配字符串开始。
\b 匹配一个单词边界,也就是指单词和空格间的位置。
例如, ‘er\b’ 可以匹配”never” 中的 ‘er’,但不能匹配 “verb” 中的 ‘er’。
\B 匹配非单词边界。
‘er\B’ 能匹配 “verb” 中的 ‘er’,但不能匹配 “never” 中的 ‘er’。
\d 匹配任意数字,等价于 [0-9]。
\D 匹配任意非数字,等价于[^\d]。
\G 匹配最后匹配完成的位置。
\s 匹配任意空白字符,等价于 [\t\n\r\f\v]。
\S 匹配任意非空字符。
\w 匹配字母数字及下划线。
\W 匹配非字母数字及下划线。
\Z 匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串。
\z 匹配字符串结束。
\n, \t, 等. 匹配一个换行符。匹配一个制表符。等
\1…\9 匹配第n个分组的内容。

常见的正则表达式

校验数字的表达式

含义 表达式
数字 ^[0-9]\*$
n位的数字 ^\d{n}$
零和非零开头的数字 ^(0|[1-9][0-9]*)$
非零开头的最多带两位小数的数字 ^([1-9][0-9]*)+(\.[0-9]{1,2})?$
正数、负数和小数 ^(\-\|\+)?\d+(\.\d+)?$
非零的正整数 ^[1-9]\d*$
^([1-9][0-9]*){1,3}$
^\+?[1-9][0-9]*$
非零的负整数 ^\-[1-9][]0-9"*$
^-[1-9]\d*$
非负整数 ^\d+$
^[1-9]\d*|0$
非正整数 ^-[1-9]\d*\|0$
^((-\d+)|(0+))$
非负浮点数 ^\d+(\.\d+)?$
^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$
非正浮点数 ^((-\d+(\.\d+)?)\|(0+(\.0+)?))$
^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$
正浮点数 ^[1-9]\d*\.\d*\|0\.\d*[1-9]\d*$
^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$
负浮点数 ^-([1-9]\d*\.\d*\|0\.\d*[1-9]\d*)$
^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$
浮点数 ^(-?\d+)(\.\d+)?$
^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$

校验字符的表达式

含义 表达式
汉字 ^[\u4e00-\u9fa5]{0,}$
英文和数字 ^[A-Za-z0-9]+$
^[A-Za-z0-9]{4,40}$
由26个英文字母组成的字符串 ^[A-Za-z]+$
中文、英文、数字包括下划线 ^[\u4E00-\u9FA5A-Za-z0-9_]+$
可以输入含有^%&’,;=?$"等字符 [^%&',;=?$\x22]+
禁止输入含有~的字符 [^~\x22]+

特殊需求表达式

含义 表达式
Email地址 ^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$
域名 [a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.?
Internet URL [a-zA-z]+://[^\s]*
^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$
手机号码 ^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$
身份证号(15位、18位数字) (^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)
帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线) ^[a-zA-Z][a-zA-Z0-9_]{4,15}$
密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线) ^[a-zA-Z]\w{5,17}$
日期格式 ^\d{4}-\d{1,2}-\d{1,2}
一年的12个月(01~09和1~12) ^(0?[1-9]|1[0-2])$
一个月的31天(01~09和1~31) ^((0?[1-9])|((1|2)[0-9])|30|31)$
钱的正则校验(支持小数点后两位、千分位,数值可以以0开头) ^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(.[0-9]{1,2})?$
钱的正则校验(支持小数点后两位、不为0开头,不支持千分位) (^[1-9]([0-9]+)?(\.[0-9]{1,2})?$)|(^(0){1}$)|(^[0-9]\.[0-9]([0-9])?$)
空白行的正则表达式 \n\s*\r
IP地址 ((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))
电驴链接 ed2k://\|file\|([^\|]+?)\|(\d+?)\|([0-9a-zA-Z]{32})\|((?:/\|sources,([^\s\|]+?)\||h=([0-9a-zA-Z]{32})\||s=([^\s\|]+?)\||p=([^\s\|]+?)\|)*)/
提取html中的超链接 (<a\\s*(?!.*\\brel=)[^>]*)(href="https?:\\/\\/)((?!(?:(?:www\\.)?'.implode('|(?:www\\.)?', $follow_list).'))[^"]+)"((?!.*\\brel=)[^>]*)(?:[^>]*)>

参考资料:

正则表达式在Python中的应用

re模块使 Python 语言拥有全部的正则表达式功能。

在设置正则表达式字符串时,建议使用 r 前缀修饰表示原始字符串。这样就不需要进行字符的转义。

s = r'^\d{3}\-\d{3,8}$'

函数速查表

函数 说明
compile(pattern, flags=0) 编译正则表达式返回正则表达式对象。
match(pattern, string, flags=0) 用正则表达式匹配字符串。成功返回匹配对象,否则返回 None。
search(pattern, string, flags=0) 搜索字符串中第一次出现正则表达式的模式。成功返回匹配对象,否则返回 None。
split(pattern, string, maxsplit=0, flags=0) 用正则表达式指定的模式分隔符拆分字符串,返回列表。
sub(pattern, repl, string, count=0, flags=0) 用指定的字符串替换原字符串中与正则表达式匹配的模式,可以用 count 指定替换的次数。
fullmatch(pattern, string, flags=0) match 函数的完全匹配(从字符串开头到结尾)版本。
findall(pattern, string, flags=0) 查找字符串所有与正则表达式匹配的模式,返回字符串的列表。
finditer(pattern, string, flags=0) 查找字符串所有与正则表达式匹配的模式,返回一个迭代器。
purge() 清除隐式编译的正则表达式的缓存。

匹配字符

re.match()只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回 None;

re.search()匹配整个字符串,直到找到一个匹配。

检索和替换

语法格式为:re.sub(pattern, repl, string, count=0, flags=0)

Python 的 re 模块提供了re.sub()用于替换字符串中的匹配项。

phone = "2004-959-559 # 这是一个国外电话号码"
num = re.sub(r'\D', "", phone)
print ("电话号码是 : ", num)
# 电话号码是 :  2004959559

repl为替换为的参数,也可以是一个函数。

# 将匹配的数字乘以 2
def double(matched):
    value = int(matched.group('value'))
    return str(value * 2)

s = 'A23G4HFD567'
print(re.sub('(?P<value>\d+)', double, s))
# A46G8HFD1134

其它常见函数

参考资料:

正则表达式在OC中的应用

带有 options 选项的 NSString

只匹配第一个,可指定是否区分大小写。可查找、替换字符串。

NSString *searchText = @"123rangeOfString";
NSRange range = [searchText rangeOfString:@"[0-9]+" options:NSRegularExpressionSearch];
if (range.location != NSNotFound) {
    NSLog(@"rangeStr:%@", [searchText substringWithRange:range]);
}
// rangeStr:123

NSRegularExpression 类

进行复杂的文本匹配、替换。

对象创建方法

// 类方法
+ (nullable NSRegularExpression *)regularExpressionWithPattern:(NSString *)pattern options:(NSRegularExpressionOptions)options error:(NSError **)error;
// 实例方法
- (nullable instancetype)initWithPattern:(NSString *)pattern options:(NSRegularExpressionOptions)options error:(NSError **)error NS_DESIGNATED_INITIALIZER;

匹配方法

- (void)enumerateMatchesInString:(NSString *)string options:(NSMatchingOptions)options range:(NSRange)range usingBlock:(void (NS_NOESCAPE ^)(NSTextCheckingResult * _Nullable result, NSMatchingFlags flags, BOOL *stop))block;
// 通过正则匹配返回一个匹配结果的数组
- (NSArray<NSTextCheckingResult *> *)matchesInString:(NSString *)string options:(NSMatchingOptions)options range:(NSRange)range;
// 返回满足条件的匹配次数
- (NSUInteger)numberOfMatchesInString:(NSString *)string options:(NSMatchingOptions)options range:(NSRange)range;
// 匹配返回的第一个结果,NSTextCheckingResult类型
- (nullable NSTextCheckingResult *)firstMatchInString:(NSString *)string options:(NSMatchingOptions)options range:(NSRange)range;
// 匹配返回的第一个结果的NSRange范围信息
- (NSRange)rangeOfFirstMatchInString:(NSString *)string options:(NSMatchingOptions)options range:(NSRange)range;

替换方法

// 用新字段替换原文本中的对应字段,并返回操作后的NSString
- (NSString *)stringByReplacingMatchesInString:(NSString *)string options:(NSMatchingOptions)options range:(NSRange)range withTemplate:(NSString *)templ;
// 用新字段替换原文本中的对应字段,并返回操作次数
- (NSUInteger)replaceMatchesInString:(NSMutableString *)string options:(NSMatchingOptions)options range:(NSRange)range withTemplate:(NSString *)templ;
- (NSString *)replacementStringForResult:(NSTextCheckingResult *)result inString:(NSString *)string offset:(NSInteger)offset template:(NSString *)templ;
+ (NSString *)escapedTemplateForString:(NSString *)string;

实例

查找第一个符合条件的字符串:

NSString *searchText = @"you wa12nt to ma23tch";
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"[0-9]+" options:NSRegularExpressionCaseInsensitive error:&error];
NSTextCheckingResult *result = [regex firstMatchInString:searchText options:0 range:NSMakeRange(0, [searchText length])];
if (result) {
    NSLog(@"%@", [searchText substringWithRange:result.range]);
}
// match:12

查询所有符合条件的字符串:

let searchString = "you wa12nt to ma23tch"
do {
    let expression = try NSRegularExpression(pattern: "[0-9]+", options: .caseInsensitive)
    let results = expression.matches(in: searchString, options: NSRegularExpression.MatchingOptions(rawValue: 0), range: NSMakeRange(0, searchString.count))
    for num in results {
        // NSRange -> Range
        let range = Range(num.range, in: searchString)
        // Range -> NSRange
        let nsrange = NSRange(range!, in: searchString)
        // Swift 4.0使用此方法来取字符串的子串
        NSLog("searchResult:%@", String(searchString[range!]))
    }
} catch _ {
}
// searchResult:12
// searchResult:23

NSPredicate 类的 matches 命令

支持复杂文本、对象等数据检索。

NSString *email = @"xiaolei.qu@hotmail.com";
NSString *regex = @"^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$";
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex];
BOOL isValid = [predicate evaluateWithObject:email];
//    [[NSArray array] filteredArrayUsingPredicate:<#(nonnull NSPredicate *)#>]