正则表达式是由普通字符和特殊字符(也叫元字符或限定符)组成的文字模板,为用来描述或匹配符合某个句法规则的字符串。在许多软件中都得到广泛的应用,当然针对不同的命令及环境,对正则表达式的支持程度也不尽相同,这里参考正则表达式 - 应用领域。有一个通识问题说明一下
"/"是JS中经常用来分隔一个正则的开始与结尾的字符,其他语言中不用做此区分;
比如:
/* JS */
/abc/ //精确匹配abc(有/符号)
/* 其他语言 */
abc //精确匹配abc(无/符号)
很多人刚开始无从下手可能是因为不清楚如何"断句",这样也就抓不住重点,感觉像听天书了。我们可以这样拆开来看,把正则表达式看成是普通字符和其他字符的集合。普通字符包括所有大写和小写字母、所有数字、所有标点符号和一些其他符号(PS:就是平时看得懂的符号);其他字符包括了常说的元字符、运算符、限定符、特殊字符等等;
下面是一个匹配以数字开头,并以 abc 结尾的字符串;
^ [0-9] + abc $
定位符 字符集 限定符 普通字符 限定符
各种字符的详细解释可参照正则表达式 - 语法 https://www.runoob.com/regexp/regexp-syntax.html 。之后稍微了解一点语法,就可以尝试自己断句了,为了少走弯路,建议参照图形化展示工具regulex对比理解。
正则表达式主要依赖于元字符.
元字符不代表他们本身的字面意思, 他们都有特殊的含义. 一些元字符写在方括号中的时候有一些特殊的意思. 以下是一些元字符的介绍:
元字符
描述
.
句号匹配任意单个字符除了换行符.
[ ]
字符种类. 匹配方括号内的任意字符.
[^ ]
否定的字符种类. 匹配除了方括号里的任意字符
匹配>=0个重复的在号之前的字符.
+
匹配>=1个重复的+号前的字符.
?
标记?之前的字符为可选.
{n,m}
匹配num个大括号之前的字符 (n <= num <= m).
(xyz)
字符集, 匹配与 xyz 完全相等的字符串.
|
或运算符,匹配符号前或后的字符.
\
转义字符,用于匹配一些保留的字符 [ ] ( ) { } . * + ? ^ $ \ |
^
从开始行开始匹配.
$
从末端开始匹配.
2.3.2 简写字符集
正则表达式提供一些常用的字符集简写. 如下:
简写
描述
.
除换行符外的所有字符
\w
匹配所有字母数字, 等同于 [a-zA-Z0-9_]
\W
匹配所有非字母数字, 即符号, 等同于: [\w]
\d
匹配数字: [0-9]
\D
匹配非数字: [\d]
\s
匹配所有空格字符, 等同于: [\t\n\f\r\p{Z}]
\S
匹配所有非空格字符: [\s]
\f
匹配一个换页符
\n
匹配一个换行符
\r
匹配一个回车符
\t
匹配一个制表符
\v
匹配一个垂直制表符
\p
匹配 CR/LF (等同于 \r\n),用来匹配 DOS 行终止符
2.3.3 零宽度断言(前后预查)
先行断言和后发断言都属于非捕获簇(不捕获文本 ,也不针对组合计进行计数).
先行断言用于判断所匹配的格式是否在另一个确定的格式之前, 匹配结果不包含该确定格式(仅作为约束).
例如, 我们想要获得所有跟在 $ 符号后的数字, 我们可以使用正后发断言 (?<=\$)[0-9.]*.
这个表达式匹配 $ 开头, 之后跟着 0,1,2,3,4,5,6,7,8,9,. 这些字符可以出现大于等于 0 次.
零宽度断言如下:
符号
描述
?=
正先行断言-存在
?!
负先行断言-排除
?<=
正后发断言-存在
?<!
负后发断言-排除
2.3.4 标志
标志也叫模式修正符, 因为它可以用来修改表达式的搜索结果.
这些标志可以任意的组合使用, 它也是整个正则表达式的一部分.
标志
描述
i
忽略大小写.
g
全局搜索.
m
多行的: 锚点元字符 ^ $ 工作范围在每行的起始.
2.3.5 优先级
在这些运算符同时出现时,按照下面的优先级进行操作。
优先级
符号
最高
\
高
( )、(?: )、(?= )、[ ]
中
*、+、?、{n}、{n,}、{n,m}
低
、$、中介字符
最低
|
2.4 进阶篇
2.4.1 贪婪匹配与惰性匹配
正则表达式默认采用贪婪匹配模式,在该模式下意味着会匹配尽可能长的子串。我们可以使用 ? 将贪婪匹配模式转化为惰性匹配模式。
贪婪模式
(.*nt) => People want to try something different.
惰性模式
(.*?nt) => People want to try something different.
常见的惰性限定符:
符号
说明
*?
重复任意次,但尽可能少重复
+?
重复1次或更多次,但尽可能少重复
??
重复0次或1次,但尽可能少重复
{n,m}?
重复n到m次,但尽可能少重复
{n,}?
重复n次以上,但尽可能少重复
谓词(NSPredicate)
NSString *regex = @"^[0-9]+$";
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex];
NSString *str = @"1314";
if ([predicate evaluateWithObject:str]) {
NSLog(@"Condition Matched");
}
NSString
NSString *searchText = @"targetString";
NSRange range = [searchText rangeOfString:@"^[0-9]+$" options:NSRegularExpressionSearch];
if (range.location != NSNotFound) {
NSLog(@"target range :%@", [searchText substringWithRange:range]);
}
NSRegularExpression
/*
typedef NS_OPTIONS(NSUInteger, NSRegularExpressionOptions) {
NSRegularExpressionCaseInsensitive = 1 << 0, //不区分字母大小写的模式
NSRegularExpressionAllowCommentsAndWhitespace = 1 << 1, //忽略掉正则表达式中的空格和#号之后的字符
NSRegularExpressionIgnoreMetacharacters = 1 << 2, //将正则表达式整体作为字符串处理
NSRegularExpressionDotMatchesLineSeparators = 1 << 3, //允许.匹配任何字符,包括换行符
NSRegularExpressionAnchorsMatchLines = 1 << 4, //允许^和$符号匹配行的开头和结尾
NSRegularExpressionUseUnixLineSeparators = 1 << 5, //设置\n为唯一的行分隔符,否则所有的都有效。
NSRegularExpressionUseUnicodeWordBoundaries = 1 << 6 //使用Unicode TR#29标准作为词的边界,否则所有传统正则表达式的词边界都有效
};
*/
NSString *searchText = @"what do you want to match string";
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^[0-9]+$" options:NSRegularExpressionCaseInsensitive error:&error];
//仅取出第一条匹配记录
NSTextCheckingResult *firstResult = [regex firstMatchInString:searchText options:0 range:NSMakeRange(0, [searchText length])];
if (firstResult) {
NSLog(@"firstResult:%@", [searchText substringWithRange:firstResult.range]);
}
//遍历所有匹配记录
NSArray *matches = [regex matchesInString:searchText
options:0
range:NSMakeRange(0, searchText.length)];
for (NSTextCheckingResult *match in matches) {
NSRange range = [match range];
NSString *mStr = [searchText substringWithRange:range];
NSLog(@"AllResult:%@", mStr);
}