iOS正则表达式探索

参考:正则表达式正则表达式30分钟入门教程正则表达式的使用方法

一、概述

正则表达式(Regular Expression)是一种文本模式,包括普通字符(例如,a 到 z 之间的字母)和特殊字符(称为“元字符”)。

正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串。

正则表达式是繁琐的,但它是强大的,学会之后的应用会让你除了提高效率外,会给你带来绝对的成就感。

二、简介

除非您以前使用过正则表达式,否则您可能不熟悉一些术语。但是,毫无疑问,您已经使用过不涉及脚本的某些正则表达式概念。
例如,您很可能使用?*通配符来查找硬盘上的文件。?通配符匹配文件名中的0个或单个字符,而 *通配符匹配零个或多个字符。像 data?.dat这样的模式将查找下列文件:

data1.dat
data2.dat
datax.dat
dataN.dat


使用*字符代替 ? 字符扩大了找到的文件的数量。data*.dat 匹配下列所有文件:

data.dat
data1.dat
data2.dat
data12.dat
datax.dat
dataXYZ.dat
ps:在OC中的结果,
`data?.dat `匹配
dat.dat
data.dat
datfdat
datagdat

`data*.dat `匹配
dat.dat
data.dat
dataa.dat
dataaa.dat
datfdat
datagdat
datahdat
我主要想说明的是.匹配任意字符
*匹配的是数量上0个或者多个(也就是说,可以没有,可以有一个,也可以有多个)
?匹配的是数量上0个或者是1个(也就是可以也可以没有)

尽管这种搜索方法很有用,但它还是有限的。通过理解 * 通配符的工作原理,引入了正则表达式所依赖的概念,但正则表达式功能更强大,而且更加灵活。
正则表达式的使用,可以通过简单的办法来实现强大的功能。下面先给出一个简单的示例:

^[0-9]+abs$

  • ^ 为匹配输入字符串的开始位置。
  • [0-9]+匹配多个数字,[0-9] 匹配单个数字,+匹配一个或者多个。
  • abc$匹配字母 abc 并以 abc 结尾,$ 为匹配输入字符串的结束位置。

示例:
匹配以数字开头,并以abc结尾的字符串。:

var str = "123abc";
var patt1 = /^[0-9]+abc$/;
document.write(str.match(patt1));

以下标记的文本是获得的匹配的表达式:

123abc

ps:这只是在文件搜索系统中的正则看,在iOS中则略有不同,所以不要在OC中测试上述正则

为什么要使用正则表达式?

典型的搜索和替换操作要求您提供与预期的搜索结果匹配的确切文本。虽然这种技术对于静态文本执行简单的搜索和替换任务已经足够了,但它缺乏灵活性,若采用这种方法搜索动态文本,即使不是不可能,至少也会变得很困难。

通过正则表达式,可以:

  • 测试字符串内的模式:
    例如,可以测试输入字符串,以查看字符串是否出现电话号码模式或信用卡号码模式。这称为数据验证。

  • 替换文本。
    可以使用正则表达式来识别文档中的特定文本,完全删除该文本或者用其他文本替换它。

  • 基于模式匹配从字符串中提取子字符串。
    可以查找文档内或者输入域内特定的文本。

例如,您可能需要搜索整个网站,删除过时的材料,以及替换某些HTML格式标记。在这种情况下,可以使用正则表达式来确定在每个文件中是否出现该材料或该HTML格式标记。此过程将受影响的文件列表缩小到包含需要删除或更改的材料的那些文件。最后,可以通过正则表达式来搜索和替换标记。

三、正则表达式的语法

下面描述了正则表达式用于匹配字符串中的模式的字符表达式,制定模式匹配多少次的模式运算符和其他匹配限制,最后一个表指定可以包含在正则表达式中的标志通过多行指定搜索行为的模式(也可以使用选项标志来指定这些标志)

表1描述了用于匹配字符串中的字符的字符序列

表格1正则表达式元字符
字符表达 描述
\a 匹配BELL, \u0007
\A 在输入开始时匹配。不同于^在\A输入中的一个新行之后将不匹配。
\b, outside of a [Set] 如果当前位置是字边界匹配。边界发生word(\w)和非word(\W)字符之间的转换处,组合标记被忽略。为了更好的字边界,请参阅。NSRegularExpressionUseUnicodeWordBoundaries
\b, within a [Set] 匹配退格,\u0008。
\B 如果当前位置不是字边界匹配。
\cX 匹配一个control-X字符
\d 匹配任何字符与Unicode通用类别的Nd(数字,十进制数字)
\D 匹配任何不是十进制数字的字符。
\e 匹配ESCAPE,\u001B。
\E 终止\Q ... \E引用的序列。
\f 匹配一个form feed,\u000C。
\G 如果当前位置在上一个匹配结束时匹配。
\n 匹配LINE FEED,\u000A。
\N{UNICODE字符名称} 匹配named character。
\p{UNICODE PROPERTY NAME} 使用指定的Unicode属性匹配任何字符。
\P{UNICODE PROPERTY NAME} 匹配任何不具有指定Unicode属性的字符。
\Q 行情所有后续字符,直到\E。
\r 匹配运送返回,\ u000D。
\s 匹配一个空白字符。空格被定义为[\ t \ n \ f \ r \ p {Z}]。
\S 匹配非空白字符。
\t 匹配水平制表符,\u0009。
\uhh 匹配字符与十六进制值hh
\Uhhhhhhhhh 匹配字符与十六进制值hhhhhhhhhh。必须提供8位十六进位数字,即使是最大的Unicode代码点\U0010ffff
\w 匹配一个字符 字符是[\ p {L1} \ p {Lu} \ p {Lt} \ p {Lo} \ p {Nd}]。
\W 匹配非字词。
\x{hhhh} 匹配字符与十六进制值hhhh。可提供1到6个十六进制数字。
\x 匹配字符与两位十六进制值hh
\X 匹配一个化身集群
\Z 如果当前位置在输入结束处,而在最后一行终止符之前,则匹配,如果存在。
\z 如果当前位置在输入结束时匹配。
\n 返回参考。匹配任何第n个捕获组匹配。n必须是模式中的数字≥ 1和≤总数量的捕获组。
\0ooo 匹配八进制字符 ooo是从一到三个八进制数字。0377是最大允许的八进制角色。领先的零是必需的; 它将八进制常数与反向引用区分开来。
[pattern] 匹配模式中的任何一个字符。
. 匹配任何角色 见并且在字符表达式表4NSRegularExpressionDotMatchesLineSeparators
^ 在一行开始匹配 见并且在字符表达式表4NSRegularExpressionAnchorsMatchLines\m
$ 在一行结束时匹配。见并且在字符表达式表4NSRegularExpressionAnchorsMatchLines
引用以下字符。必须引用被视为文字的字符是* ? + [ ( ) { } ^ $ \ . /

正则表达式运算符

表2正则表达式运算符
操作 描述
交替 (甲 乙)要么匹配甲或乙。
* 0或者是更多次数的匹配
+ 1或更多次 匹配尽可能多的次数。
匹配零次或一次
{n} 完全匹配n次
{n,} 至少匹配n次 匹配尽可能多的次数。
{n ,m} n和m之间的匹配。匹配尽可能多的次数,但不能超过m。
*? 匹配0或更多次 匹配尽可能少的次数。
+? 比赛1次以上 匹配尽可能少的次数。
?? 匹配零次或一次。更偏好零。
{n}? 完全匹配n次
{n,}? 匹配至少n次,但不超过整体模式匹配所需。
{n,m}? n和m之间的匹配。匹配次数尽可能少,但不小于n。
*+ 匹配0次以上。在第一次遇到时,尽可能多地匹配,即使整体匹配失败(Possessive Match)也不要重试。
++ 匹配一次以上 possessive match
?+ 匹配零次或一次。possessive match
{n}+ 完全匹配n次
{n,}+ 至少匹配n次possessive match
{n,m}+ n和m之间的匹配次数,possessive match
(...) 捕获括号。匹配圆括号子表达式的输入范围在匹配后可用
(?:...) 非捕获括号。对包含的模式进行分组,但不提供匹配文本的捕获。比捕捉括号更有效率。
(?>...) 原子匹配括号。括号子表达式的第一个匹配是唯一一个尝试; 如果它不会导致整体模式匹配,请在“ (?>” 之前的位置备份搜索匹配
(?# ... ) 自由格式的评论(?# comment )。
(?= ... ) 先行断言 如果括号内的图案在当前输入位置匹配,但不会提前输入位置,则为真。
(?! ... ) 负面的预言断言。如果括号中的图案在当前输入位置不匹配,则为真。不提高输入位置。
(?<= ... ) 瞻性断言 如果括号中的模式与当前输入位置之前的文本匹配,则匹配的最后一个字符就是当前位置之前的输入字符。不改变输入位置。由look-behind模式匹配的可能字符串的长度不能是无限制的(否*或+运算符。
(?<! ... ) 负面看法断言。如果括号中的模式与当前输入位置之前的文本不匹配,则匹配的最后一个字符就是当前位置之前的输入字符。不改变输入位置。由look-behind模式匹配的可能字符串的长度不能是无限制的(否*或+运算符。)
(?ismwx-ismwx: ... ) 标志设置。使用指定的启用或禁用的标志来评估括号中的表达式。标志在标志选项中定义。
(?ismwx-ismwx) 标志设置。更改标志设置。更改适用于设置后的模式部分。例如,(?i)更改为不区分大小写的匹配。标志在标志选项中定义。

模板匹配格式

本类提供了使用模板匹配的技术既可变和不可变的字符串查找和替换的方法。表3描述了语法。

表3模板匹配格式
字符 描述
$n 捕获组n的文本将被替换为$ n。n必须>= 0和不大于捕获组的数量。一个$没有后面的数字没有什么特别的意义,并且会以替代文本的形式出现在自己身上$。
将以下字符视为文字,抑制任何特殊含义。替换文本中的反斜杠转义只适用于'$'和'',但可以用于任何其他字符而不会产生不良影响。

替换字符串被视为模板,$0被匹配范围$1的内容,第一个捕获组的内容替换,等等。除了表示捕获组数量所需的最大值之外的其他数字将被视为普通字符,$不会跟随数字。反斜杠将难逃都$和\

标记选项

以下标志控制正则表达式匹配的各个方面。
可以使用(?ismx-ismx)模式选项在模式中指定这些标志值。当使用选项标志初始化时,可以为整个模式指定等效的行为。
NSRegularExpressionNSRegularExpressionOptions

表4 标记选项
flag(pattern) 描述
i 如果设置,匹配将以不区分大小写的方式进行。
X 如果设置,允许在模式中使用空格和#comments
s 如果设置,.模式中的“ ”将匹配输入文本中的行终止符。默认情况下,它不会。请注意,carriage-return / line-feed pair文本中的内容表现为单行终止符,并将匹配.正则表达式模式中的单个“ ”
m 以模式控制“ ^”和“ $” 的行为。默认情况下,这些仅分别匹配输入文本的开始和结束。如果设置了这个标志,“ ^”和“ $”也将在输入文本的每一行的开头和结尾相匹配。
w 控制模式中的行为\b。如果设置,则根据Unicode UAX 29“文本边界”中发现的词的定义找到字边界。默认情况下,通过将字符简单地分类为“单词”或“非单词”来识别字边界,其近似于传统的正则表达行为。使用两个选项获得的结果在空格和其他非字符字符的运行中可能会有很大差异。

性能

NSRegularExpression
实现了非确定性有限自动机匹配引擎。因此,当尝试执行匹配时,包含多个*或+运算符的复杂正则表达式模式可能会导致较差的性能 -特别是无法匹配给定的输入。有关更多信息,请参阅“ICU用户指南”“性能提示”部分

四、OC中的Regular表达式NSRegularExpression

NSRegularExpression被设计为不可变的和线程安全的,因此可以一次使用单个实例来匹配多个线程上的操作。但是,在匹配操作的过程中,无论是从另一个线程还是在迭代中使用的块内,不应该在其上操作它的字符串。

1、创建正在表达式
2、获取正则表达式和选项
3、使用正则表达式搜索字符串

- firstMatchInString:options:range:
返回字符串指定范围内正则表达式的第一个匹配项。

4、使用正则表达式替换字符串
5、在字符串中转义
  • + escapedTemplateForString:
    通过根据需要添加反斜杠转义来返回模板字符串,以保护符合模式元字符的任何字符

  • + escapedPatternForString:
    通过根据需要添加反斜杠转义来返回字符串,以保护符合模式元字符的任何字符。

6、自定义替换功能
7、常数

五、optionals

1、NSMatching 选项

匹配选项常量指定表达式匹配方法的报告,完成和匹配规则。所有使用正则表达式搜索或替换值的方法都使用这些常量。

2、NSRegular表达式选项

五、正则表达式的使用

1、谓词(NSPredicate)创建正则表达式

使用它来判断用户输入的字符串是否为合法的:

// 编写正则表达式:只能是数字或英文,或两者都存在
NSString *regex = @"^[a-z0-9A-Z]*$";
// 创建谓词对象并设定条件的表达式
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex];
// 判断的字符串
NSString *str = @"Hello100";
// 对字符串进行判断
if ([predicate evaluateWithObject:str]) {
    NSLog(@"Match");
}
2、NSString实例方法

使用rangeOfString:options:方法可以做到,具体看例子:

NSString *phoneNo = @"13143503442";
NSRange range = [phoneNo rangeOfString:@"^1[3]\\d{9}$" options:NSRegularExpressionSearch];
if (range.location != NSNotFound) {
    NSLog(@"%@", [phoneNo substringWithRange:range]);
}

rangeOfString:options:会返回一个NSRange,用来接收匹配的范围,当匹配不到结果时,将会返回一个NSIntegerMax最大值,也就是NSNotFound,因此我们可以用它来判断用户输入的内容是否符合规则。

3、NSRegularExpression类创建正则表达式

我们可以使用正则来过滤并获取我们想要的特定部分,实现方法也很简单,可以用到NSRegularExpression这个类实现:

NSString *url = @"1229436624@qq.com";
NSError *error;
// 创建NSRegularExpression对象并指定正则表达式
NSRegularExpression *regex = [NSRegularExpression
                              regularExpressionWithPattern:@"[^@]*\\."
                              options:0
                              error:&error];
if (!error) { // 如果没有错误
    // 获取特特定字符串的范围
    NSTextCheckingResult *match = [regex firstMatchInString:url
                                                    options:0
                                                      range:NSMakeRange(0, [url length])];
    if (match) {
        // 截获特定的字符串
        NSString *result = [url substringWithRange:match.range];
        NSLog(@"%@",result);
    }
} else { // 如果有错误,则把错误打印出来
    NSLog(@"error - %@", error);
}

这个例子是从字符串里检索出以“@”开头“.”结尾的区间字符串,最后检索出来的字符串结尾包括“.”,因此此例子最终输出结果为“qq.”

4、NSRegularExpression类之抓取多个结果

当一个字符串有多个符合特定规则的字符,我们可以分别获取到符合特定规则的字符:

NSString *regex = @"\\-\\d*\\.";
NSString *str = @"-34023242.-34203020.";
NSError *error;
NSRegularExpression *regular = [NSRegularExpression regularExpressionWithPattern:regex
                                                                         options:NSRegularExpressionCaseInsensitive
                                                                           error:&error];
// 对str字符串进行匹配
NSArray *matches = [regular matchesInString:str
                                    options:0
                                      range:NSMakeRange(0, str.length)];
// 遍历匹配后的每一条记录
for (NSTextCheckingResult *match in matches) {
    NSRange range = [match range];
    NSString *mStr = [str substringWithRange:range];
    NSLog(@"%@", mStr);
}

从指定字符串中获取以“-”开头以“.”结尾的字符,因为可能有多个符合特定规则的字符串,因此我们需要把它们遍历出来,具体输出结果如下

017-05-02 16:38:52.309 Juny_regularDemo[1669:190937] -34023242.
2017-05-02 16:38:52.310 Juny_regularDemo[1669:190937] -34203020.

总结:一般来说,判断用户输入的是否合法,只需要方法一就可以了。如果是需要捕获用户输入的特定内容,可以用方法二或者方法三、四,如果可能有多个捕获结果,那么可以使用方法四,否则使用方法二。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,482评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,377评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,762评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,273评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,289评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,046评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,351评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,988评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,476评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,948评论 2 324
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,064评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,712评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,261评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,264评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,486评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,511评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,802评论 2 345

推荐阅读更多精彩内容