为什么当输入不在数组的数时search函数会使b变成-1, 是所有的search函数都是这样还是根据不同程序变化?

正则表达式(广为所知的“regex”)是一个字符串或一个字符序列来说明一种模式,把它作为一个搜索字符串-非常强大!

在一个文本编辑器或文字处理器中普通的旧式搜索只允许你进行简单的匹配。正则表达式可以实现这样简单的搜索,它还能让你更进一步地按模式搜索,例如,在两个数字后跟一个字母,或者,三个字母后跟一个连字符。

这种模式匹配能让你做更有用的事,如验证字段(电话号码,邮箱地址),检查用户输入,执行更高级的文本操作等等。

如果你渴望了解更多关于正则表达式在iOS中的用法,看一些本教程之外的内容--不需要有相关的经验。

在这篇NSRegularExpression教程中,你将实现一个在文本中按模式搜索的功能,用你希望的值替代那些匹配的值,验证你的输入信息,在文字块中找到并高亮显示复杂字符串。

此外,我还将给你提供一个NSRegularExpression Cheat Sheet PDF,你可以打印出来,在你开发过程中作为参考,Swift playground 包含了很多例子,你能用它试验出许多不同形式的正则表达式!实际上,所有正则表达式的例子都会出现在本教程中,用很生动的例子展现在playground中,一定要查看它们哦。

闲话少说,是时候来处理正则表达式了。

Note:如果你已经有正则表达式基础了,可以跳过头部,直接看Implementing Regex in 的!请下载下来查看。

除此之外,下面是cheat sheet的缩小版,和一些简短的解释:

  • \w匹配任意“word-like”字符,包括数字,字母,下划线,不过不能匹配标点符号和其他字符。hello\w会匹配”hello_“,”hello9”和”helloo”,但不匹配”hello!”。

  • \d 匹配数字,大部分情况下是[0-9]\d\d?:\d\d会匹配时间格式的字符串,比如”9:30“和”12:45“。

  • \b 匹配额外的字符,例如空格,标点符号。to\b 会匹配”to the moon”和“to!”中得“to”,但是不会匹配“tomorrow”。\b 用在整个单词的匹配方面和方便。

  • ^用在一行的开始。记住,这个特殊的^不同于方括号中的^!例如,^Hello 会匹配字符串“Hello there”,而不会去匹配“He said Hello”。

  • 花括号{}包含了匹配的最大和值最小个数。例如,10{1,2}1会匹配“101”和“1001”,而不会匹配“10001”,因为匹配的最小个数为1,最大个数为2。He[LI]{2,}o会匹配“HeLLo”和“HellLLLIo”和任意其他的“hello”添加多个L的变种,所以没有限制,因为,最少的个数是2,最大的个数没有设置。

有了这些基础知识,就可以继续向下学习了。

是时候你自己亲自体验一下这些例子了,它们都包含在上面提到的Playground里了。

既然你有了这些基础,就在APP中应用正则表达式吧。

如果你还没有这样做,下载  开始本教程吧。下载下来,用Xcode打开并运行它。

APP的UI部分已经完成了大部分,但这个APP的核心功能依赖与正则表达式,这个还没有…!你的任务就是添加正则表达式来时这个APP更出色。

下面所视的几个截图的例子展示了这个应用的内容:

这个简单的应用涵盖两个正则表达式的通用用例:
1.执行搜索:高亮显示搜索和替换

这就开始直接使用正则表达式:文本搜索

这是一个搜索/替换的简单功能的概述:

  • 用户输入一些信息并点击“Search”按钮。

  • 如果用户选择了SearchOptionsViewController中的“Replace”选项,APP会执行搜索并替换文本中所有匹配的内容,不再是高亮显示结果。

你也可以用text kit来实现高亮的功能。确保找到 来查看更多内容。

还有一个“Bookmark”按钮,允许用户高亮显示文本中的日期,时间,位置。为简单起见,不会涵盖文本中出现的各种格式的日期时间位置。在教程的结尾你可以实现这个高亮功能。

开始实现这个功能的第一步是跳转到标准字符串正则表达式的NSRegularExpression对象。

代码为NSRegularExpression增加了一个便利构造方法。它通过SearchOptions实例的不同设置来做一些正确的配置。

  • 如果用户请求一个完整的单词,APP把正则表达式包含在\b字符组之内。在单词边界字符组中放入\b,因此,搜索模式之前和之后加上\b就会返回一个完整的单词搜索(举例来说,模式“\bcat\b”只会匹配单词“cat”,而不会匹配“catch”)。

如果以任何理由都不能创建NSRegularExpression,构造函数就会失败并返回nil。既然你有了NSRegularExpression对象,你就能伴随着其他操作来匹配文本了。

首先,这个方法捕获UITextView中得当前文本,并计算文本的长度。可能会把正则表达式应用在文本的一个子集上,所以你需要指定一个范围。这种情况下,你要用字符串的整个长度才能保证正则表达式被运用在整个文本上。

不可思议的事发生在调用stringByReplacingMatchesInString的时候。这个方法返回一个新字符串并没有改变旧字符串。然后,这个方法给UITextView设置这个新字符串,所以用户看到了正确的结果。

这儿就一步一步的解释上面的代码:

2.然后,创建一个整个文本长度的NSRange,并删除已经有背景色的文本的背景色,

3.正如找到和替换,紧接着用你的便利构造方法创建一个正则表达式,获取一个存放正则表达式与textview中文本匹配的所有匹配项的数组。

4. 轮询每一个匹配项(把它们转换成NSTextCheckingResult对象),并为每一项添加黄色背景。

编译和运行你的APP,试着搜索一些不同的单词和词组!整个文本的匹配项都会高亮显示,就像下面的图片所示:

试着使用不同的选项(options)搜索单词“the”看看效果。注意,例如,当搜索整个单词时,‘them’中得‘the’不会高亮显示。
再者,测试一下搜索和替换功能,看看你的文本字符串是怎样如期替换的,试一下’match case‘和‘whole words’选项。

高亮显示和替换都是很有用的,但是你怎样在你的APP中更有效的利用正则表达式呢?

许多Apps都有某种用户输入,比如用户输入Email地址或电话号码。你会对这个用户的输入执行某种级别的数据验证,确保数据的完整,如果用户输入中有错误,通知用户。

对这类数据验证,正则表达式是可以完美解决的,因为他们在模式匹配方面是如此出色。
有两个东西你需要添加到你的APP,验证模式本身,提供一个机制验证用户输入和和这些模式。确保这些对用户来说简单易用,你的APP内的验证不区分大小写,这样,你就可以在你的模式中只使用小写字母。

作为练习,试着想出一个正则表达式来验证下面的字符串(不用考虑大小写问题):

你是怎么想到需要的正则表达式的?如果你在这儿卡住了,回过头去看看上面的小抄(cheat sheet)上的片段,上面的方案会对你有帮助的.

下面的剧透会展示给你你要用的正则表达式。在向下看之前,首先你自己先理解它,然后检查你自己的结果!

为了创建正则表达式来验证first name ,首先要匹配字符串的开头,然后匹配一个从a到z范围的字符组,最后匹配字符串的结尾来确保它是在1到10个字符的长度。
Note:此处你不必担心大小写问题--当实例化正则表达式时,会处理它。
最后,需要一个捕获组来匹配19或20,后面跟两个数字字符。
你就得到了创造性的正则表达式。也有另外的方式解决上面的问题,比如用\d代替[0-9]。当然了,只要能正常工作的方案就是***的方案。
Note:实际应用中,你很可能不会用正则表达式来验证时间(更不会在一个日期范围内检查它)。相反,你很可能会使用NSDateFormatter来从字符串解析成日期,然后比较解析的NSDate和引用的日期。
既然你掌握了这个模式,你需要验证每个text field中输入的文本。

这与在SearchViewController.swift所做很相似,从regexes数组中拿取相关的正则表达式开始,去掉用户在textfield中输入内容中含有的所有空白字符,然后创建一个包含整个文本的范围。

运行程序,点击右下方的Contacts 按钮,试着在sign up中输入一些信息,当你完成每个field,你会看到它的文本依据是否有效变绿或变红效果如下方截图:

上面的代码用了stringByTrimmingCharactersInSet来删除用户输入的开头和结尾的空格-否则如果有空格在的话就会验证失败。

这是stringByTrimmingCharactersInSet的一个固定用法,但是作为怎么处理正则表达式的教程,还有一个更有趣的方向,考虑怎样通过正则表达式来实现。

去掉空格,一个小插曲。

要么更新你的模式来处理首尾处的空格,要么在你一个用验证模式之前创建并应用另一个模式来去掉首尾的空格。第二种方法保证了验证模式的简单简洁,也可以在它的方法内部重构,你需要的只是一个正则表达式。

你想到一个去除首位空格的正则表达式了吗?在你看下面的结果前自己试一下。

好极了,模式^\s+会发现开头的空格,\s+$会找到结尾处的空格。现在有了一个匹配空格的正则表达式,是时候用用它了。在SignUpViewController.swift的底部,类定义花括号外面,添加如下代码:

就像你在NSRegularExpression中所作的一样,添加一个String的实例方法,在我们看这个方法如何实现之前,改变validateTextField,通过改变下面这个去除空格的行使用这个新方法:

这个String的新方法用上边的模式创建了一个正则表达式,返回一个匹配出都用$1替代的新字符串,但是$1是什么意思呢?

当你有个正则表达式的捕获组(用小括号()来表示),你可以用$和数字来引用组的内容。正则表达式文档指出叫反引用。数子指出引用那个捕获组。
作为例子,给出一个正则表达式:

$1的值会试123$2的值会是0089,多有用的工具!

回头看这个空格的例子,$1只是用它自身--一个捕获组来取代空格,实际什么也没做?
这种情况下,圆括号中的?:告诉正则表达式引擎创建一个非捕获组。也就是说,匹配的文本不会像正常情况下那样存在缓冲区。
既然第一个捕获组是一个非捕获组,引擎自然不会捕获任何东西--因此它是空的!这样,引擎匹配空格结束,去掉空格,有效的移除了首尾的空格。

当然了,这是捕获值的特殊用法。实际上你可以只用一个空字符串,“”,作为你的模板值。

举个更实际的例子,假设你想要选择一个文件中你所有的用户ID,让四位数字的部分在三位数字的前面,你想要两组数字之前的间隔更大一些,一个连字符换成两个?更具体的来说是你想这样:

你回怎样做呢?下面的剧透就是答案。但是你先自己试试。

在这个例子包含的playground结尾处,你能看到这个例子的效果。

Note:这个正则表达式在name和ID之间允许任意数量的空格,在“ID:”和真正的ID值中间也是如此。

如果你一直纠结于非捕获,捕获和反向引用,在playground中试试下面的不同情况,看看会是什么结果(建议:你可以使用‘replaceMatches’函数):

还没有实现导航条上的书签按钮。当用户点击它时,APP应该高亮显示文本中的日期,时间,位置。

上面这个方法调用三个其他的辅助方法来给日期,时间,地点加下划线。如果你看向者三个辅助方法,你会看到他们都是空方法!

首先,填上每个方法的实现。用下面的内容替换他们:

每个方法调用NSRegularExpression的一个工厂方法来创建一个合适的正则表达式。这些还不存在,但是这是一个方便的地方封装这个行为。这个方法找到匹配项,调用highlightMatches来给文本中的每个字符串着色和添加下划线。如果你有兴趣看它如何实现,查看它的实现。

现在你来实现这些模式,这是一些你需要的内容:

  • 全称和缩写月的名字(如,Jan或January,Feb或February等),之后跟着一两个数字(如:x或xx).日可能是序数词(如:1st, 2nd, 10th, 21st等),之后跟一个逗号作为分隔符,然后是一个四位的数字(如,xxxx).在日月年两两之间可能包含零至多个空白。例如:March 13th, 2001。

  • 找出像“9am” 或 “11 pm”的简单时间:一两位数字跟着一个或多个空格,再后面跟着小写的“am” 或 “pm”。

  • 至少一个字符的任意单词,紧跟着一个逗号,再跟着零个或多个空格,再跟着两个大写的英语字母组合。例如“Boston, MA”。

你可以用playground试验一下。看是否能勾勒出需要的正则表达式!

这个模式被|(或)分成了两部分。意味着或者第一部分匹配或者第二部分匹配。

第一部分内容:(\d{1,2}[-/.]\d{1,2}[-/.]\d{1,2})。意味着两个数字之后跟着一个-或/或.。之后再跟着两个数字,再跟着-或/或.,最后跟两个数字。

接下来是 \\s*\\d{1,2}(st|nd|rd|th)?,它会匹配零个或多个空格,后面跟一到两个数字,再之后跟着一个可选的序数词后缀。例如,它会匹配“1” 和 “1st”。

最后,[,]\\s*\\d{4}会匹配一个逗号,之后会跟着零个或多个空格,再之后跟着一个表示年的四位数字。

多恐怖的一个正则表达式!不过,你可以看到正则表达式的简洁,和把大量信息包装成一个看似神秘的字符串的功能的强大!

作为练习,看看你能否根据上面的要求解释一下这个正则表达式模式。

编译并运行这个APP,点击Bookmark图标。你应该会看到高亮显示的日期,时间,位置,如下所示:

这个例子就到这儿了,你能明白为什么这个对于时间的正则表达式不能正确进行更通用的搜索吗?按现在的情况,它不会匹配3:15pm,它会匹配28pm。
这是一个有挑战性的问题!想想怎样重写这个关于时间的正则表达式,来让它匹配更通用的时间格式。
具体来说,你的答案应该匹配12小时制的ab:cd

下面是一个可行的答案,但是你自己先试一下。在附带的playground尾部看一下它的效果。

是你依据上边的教程开发的最终例子 。

恭喜你!现在你已经有了一些正则表达式使用方面的实践经验。

正则表达式是强大的,使用它也很有趣,他们很像解决数学问题。正则表达式的弹性让我们有很多种方法来创建一个模式去适应你的需求,例如过滤输入字符串的空格,在解析前去除HTML或XML标签,或者是,找出特殊的XML或HTML标签等等!
有很多现实世界的字符串例子,你可以用正则表达式去验证。

作为最后的练习,试图解开下面这个正则表达式来验证一个邮箱地址():

乍看起来,它看起来是一堆杂乱的字符串,但是,用你新发现的知识(下面的链接很有用),你会一步一步理解它,并成为正则表达式的高手!

如果传入与此格式匹配的字符串,则它将会被正确地解析。

更多信息和详细文档可以在 GitHub 上找到 。

另一个范围插件是 Isaac Cambron 的库 Twix。 它具有许多与范围相关的特性,并且擅长格式化范围。 例如,

所有选项和特性的完整文档在。

像这样在 npm 上可用:

或者只是从获取 JS 文件。

插件可用于显示日期/时间范围的准确的人类可读的表示形式:

要获取原始数字值而不是字符串,则将 true 值作为第三个参数传给该方法:

当安装后,它会封装 moment,且 moment 将可以格式化和解析 Jalaali 的年月。 这是一个简短的示例:

当安装时,它将会封装 moment,且你将可以解析 Hijri 日期。 这是一个简短的示例:

此插件将会允许你创建基于长度的间隔(天、周等)和基于日历的间隔(月份的日期、年份的月份等)。

它提供了一个 matches 函数来测试日期是否根据规则集重现,还提供了生成器函数来获取系列中的下一个和上一个日期。

仓库、文档和更多示例可以在 上找到。

如果想尝试像 Twitter 一样格式化推文的时间,则可以使用 的 插件。

这是显示人类可读的时间戳的长短版本的简单方法。

是的,它可以进行智能多元化。

如果需要、日历或学术季度,可以使用 的 插件。

最简单的是,只需在任何 moment 对象上调用 fquarter 方法。 它返回格式化的字符串,其中四月是第一季度。

可以将任何月份作为起始季度,例如七月:

如果需要日历季度,则从一月开始:

该插件提取日期/时间字符串的格式。

这样就可以创建智能日期输入,让用户设置日期/时间,并提取用户的首选格式以供将来使用。 在 上找到其用法示例。

该插件由 编写。 链接: | 。

For example, 该插件会将日期/时间四舍五入到给定的时间间隔。

是一个通过模式操作日期的插件。 可以对 Moment 实例的各个部分(小时、月份等)使用基本操作(设置/添加/减少)。

可选的参数可以指定自定义的模式并强制使用严格的模式(默认情况下,在传入的字符串中非字母字符不是必需的)。

当安装后,它将会可以封装 moment,且将可以格式化和解析台湾年份。 这是一个简短的示例:

这是一个 Moment.js 库,允许 Moment 在西方工作周中进行操作:7 天工作周,其中周六和周日为非工作日。

如果要以较短的方式格式化时间,可以使用 的 插件。

如果该日期在将来或过去过长,它将会显示为:

这个 moment-feiertage 是一个 Moment.js 插件,用于确定日期是否为德国假期。 假期取自维基百科(德国)。 确定日期是否为假日有点复杂,因为宗教节日每年变化,在德国的 16 个州内也不同。

我要回帖

更多关于 查询一个数据是否在数组中 的文章

 

随机推荐