在Swift中如何使用正则表达式详解

前言

正则表达式,又称规则表达式。(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表通常被用来检索、替换那些符合某个模式(规则)的文本。

正则表达式(Regular expression, regex)允许我们在几秒钟内在成千上万文档间进行复杂检索与替换,自从诞生50多年来它依旧广泛使用。

Swift虽然是一个新出的语言,但却不提供专门的处理正则的语法和类。所以我们只能使用古老的NSRegularExpression类进行正则匹配。

在这篇文章中,我会讲解在Swift中正则表达式的基本用法。我们会从易到难,详细讲解一些最重要的正则表达式语法,以及一些有用的扩展。

NSRegularExpression:如何在字符串中匹配正则表达式

NSRegularExpression类让我们可以用正则表达式查找替换子字符串,它可以简洁灵活地描述文本。例如,如果你想从"My name is Taylor Swift"中提取出"Taylor Swift",可以写一个匹配文本“My name is”的正则表达式,它的后面可以是任何文本,之后把它传递给NSRegularExpression类。

具体可见下面代码。注意我们要提取出的是第二范围,因为第一范围是匹配的字符串,而第二范围才是"Taylor Swift"部分。

do {
 let input = "My name is Taylor Swift"
 let regex = try NSRegularExpression(pattern: "My name is (.*)", options: NSRegularExpression.Options.caseInsensitive)
 let matches = regex.matches(in: input, options: [], range: NSRange(location: 0, length: input.utf16.count))

 if let match = matches.first {
  let range = match.range(at:1)
  if let swiftRange = Range(range, in: input) {
   let name = input[swiftRange]
  }
 }
} catch {
 // regex was bad!
}

正则表达式的详细讲解

让我们从几个简单例子开始,方便不熟悉的人了解正则表达式。正则表达式,简称regex,用于让我们在字符串中进行模糊检索。例如我们知道”cat”包含”at”,但如果我们检索所有以“at”结尾的3字母单词该怎么做呢?

正则表达式就用于解决这个问题,尽管由于Objective-C的基础,它们的语法有些不太灵巧。

1. 首先,定义你想检索的字符串:

let testString = "hat"

之后创建NSRange实例来表示整个字符串的长度

let range = NSRange(location: 0, length: testString.utf16.count)

这里使用utf16来避免类似表情符号等带来的问题

2. 之后使用正则表达式语法创建NSRegularExpression实例

let regex = try! NSRegularExpression(pattern: "[a-z]at")

[a-z]在正则表达式中用于指定a到z之间任意字母。实际使用中你可能会提供一个无效的正则表达式,但是这里我们有了一个硬编码的正确正则表达式,所以就不需要查找错误了。

3. 最后在创建好的正则表达式调用firstMatch(in:),输入要检索的字符串,一些特殊选项,和字符串的范围。如果字符串匹配正则表达式,就会返回数据,否则就是nil。所以如果你想检查字符串是否完全匹配,就用firstMatch(in:)的结果和nil比较:

regex.firstMatch(in: testString, options: [], range: range) != nil

这里必须要用到NSRange——尽管这个API是为NSString设计,和Swift衔接的不太好。Swift String Manifesto可能会替换它,但看起来还要很久。

正则表达式“[a-z]at”会成功匹配“hat”,和“cat”, “sat”, “mat”, “bat”等等——我们只要关注想匹配什么,NSRegularExpression会处理好它。

让NSRegularExpression用起来更简单

接下里会展示更多的正则表达式语法,首先来看看如何让NSRegularExpression稍微好用一些

现在我们的要3行Swift代码来匹配一个简单字符串

let range = NSRange(location: 0, length: testString.utf16.count)
let regex = try! NSRegularExpression(pattern: "[a-z]at")
regex.firstMatch(in: testString, options: [], range: range) != nil

我们可以从多种方式改进,不过最有效的是扩展NSRegularExpression,让创建和匹配表达式更简单。

首先第一行:

let regex = try! NSRegularExpression(pattern: "[a-z]at")

我提到过,创建一个NSRegularExpression实例可能导致错误,因为可能会提供一个非法的正则表达式。比如[a-zat,忘记了]

结果就是,通常会用try!创建NSRegularExpression实例。然而这会导致lint工具(如SwiftLint)的破坏。所以好一点的方法是创建一个方便的初始化,能正确创建正则表达式,或者在开发时能生成一个断言失败。

extension NSRegularExpression {
 convenience init(_ pattern: String) {
  do {
   try self.init(pattern: pattern)
  } catch {
   preconditionFailure("Illegal regular expression: \(pattern).")
  }
 }
}

注意:如果你的app需要用户写正则表达式,你需要使用NSRegularExpression(pattern:)初始化,这样可以更好的处理错误。

之后这些行:

let range = NSRange(location: 0, length: testString.utf16.count)
regex.firstMatch(in: testString, options: [], range: range) != nil

第一行创建了一个包含整个字符串的NSRange,第二行则是在文本中查找first match。但这是很笨的方法,因为大多时候你想查找输入的整个字符串,用firstMatch(in:)与nil判定会弄混你的意图。

所以,用另一个扩展来替代它,它把下面代码包含在一个简单的matches()方法中。

extension NSRegularExpression {
 func matches(_ string: String) -> Bool {
  let range = NSRange(location: 0, length: string.utf16.count)
  return firstMatch(in: string, options: [], range: range) != nil
 }
} 

如果你把这两个扩展合并,就可以更轻松的创建和检索正则表达式了。

let regex = NSRegularExpression("[a-z]at")
regex.matches("hat") 

我们可以进一步通过运算符重载让Swift包含的,~=,运算符适用于正则表达式:

extension String {
 static func ~= (lhs: String, rhs: String) -> Bool {
  guard let regex = try? NSRegularExpression(pattern: rhs) else { return false }
  let range = NSRange(location: 0, length: lhs.utf16.count)
  return regex.firstMatch(in: lhs, options: [], range: range) != nil
 }
}

通过上面代码,我们可以在一句话的左边使用任意字符,右边用正则表达式。

"hat" ~= "[a-z]at"

注意:创建NSRegularExpression实例会有一定消耗,所以如果你想要反复使用一个正则表达式,最好把NSRegularExpression实例保存起来。

正则表达式语法学之旅

我们已经使用了[a-z]来表示“a”到“z”之间任意字母,在正则表达式中这是一个字符类。它让你指定要匹配的一组字母,可以通过制定的字母列表匹配,或者通过一段字符范围匹配。

正则表达式范围不一定是整个字母表,你可以用[a-t] 来排除“u”到“z”之间的字母。另外,如果你想特别指定一些字母,只需要像这样单独列出它们:

[csm]at

正则表达式默认区分大小姐写,也就是说“Cat”和“Mat”不会在“[a-z]at”被匹配。如果你想忽略大小写,可以使用“[a-zA-Z]at”,或者创建你自己的NSRegularExpression对象,并标记.caseInsensitive

除了大小写以外,你可以通过字符类指定数字范围。最常用的是[0-9]表示任何数字,或[A-Za-z0-9]表示任何字母数字混编字符,也可以用[A-Fa-f0-9]来表示16进制数字。

如果你想匹配一个字符序列,还需要一个叫做量词(quantifier)的概念。它用于表示字符出现的数量。

最常用的是星号量词,*,意思是匹配0个或更多。量词在它们修饰的字符后出现,就像下面这样:

let regex = NSRegularExpression("ca[a-z]*d")

这句话先查找“ca”,之后是0或多个从“a”到“z”的字母,最后是“d”——它能匹配“cad”, “card”, “clamped”等等。

除了*之外,还有2个类似的量词 + 和 ? 。 + 意味着“1个或更多”,与 * 的“0个或更多”有点区别。而 ? 的意思是”0或1个”

这些量词是正则表达式基础内容,希望大家能确实理解它们的区别,比如下面3个正则表达式

  • ca[a-z]*d
  • ca[a-z]+d
  • ca[a-z]?d

并想想如果给出字符串“cd”或“clamped”,哪些能够匹配。

如果需要,可以用大括号 { 和 } 来更详细的指定匹配数量,比如[a-z]{3}意味着匹配3个小写字母。

考虑一个电话号码格式比如111-1111。如果要正好匹配这个格式,用[0-9-]+是行不通的。所以我们需要用这样的正则表达式[0-9]{3}-[0-9]{4},即先是3个数字,之后连接号,之后4个数字。

此外还可以用大括号指定范围,它可以是有界限的或无界限的。比如[a-z]{1,3}代表匹配1,2,或3个小写字母。[a-z]{3,}代表匹配3个或更多个

最后,元字符(meta-characters)是特殊字符,正则表达式中有特别的意义,在这里介绍其中几个使用最频繁的。

首先其中是最常用,也是最滥用的 . 字符。它可以匹配除了换行符以外任意一个字符。比如正则表达式c.t可以匹配“cat”,但不能匹配“cart”。如果你把 . 和 * 量词共同使用,就意味着匹配1个或多个除了换行符以外所有字符,这可能是你最常见的正则表达式了。

.* 常用的原因也显而易见:不需要具体设计一个特别的正则表达式,.* 就可以匹配几乎一切了。然而问题是,特定化本来就是正则表达式的要点之一,你可以在文本中精确查找一些字符并操作它们。而太多人完全依赖 .* ,却没有意识到这可能会给他们的表达式带来难以察觉的错误。

用前面电话号码的例子来说,我们用[0-9]{3}-[0-9]{4}匹配类似555-5555的电话号码。考虑到有些人会写成“555 5555”或“5555555”,我们可能就会把正则表达式条件放宽一些,改成[0-9]{3}.*[0-9]{4}

但是这样就带来一个问题,它会匹配“123-4567”, “123-4567890”, 或 “123-456-789012345”。为了让[0-9]{3}与[0-9]{4}匹配上,.* 会匹配尽可能多的字符

所以这里要用字符类与量词,比如[0-9]{3}[ -]*[0-9]{4},代表3个数字,之后0个或更多空格与连接线,之后4个数字。或者使用不包含字符类,即用它来匹配数字以外的字符,如[0-9]{3}[^0-9]+[0-9]{4},会匹配空格,连接线,斜杠等等,而不会匹配数字。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • Swift中使用正则表达式的一些方法

    我使用Swift有段时间了,但最让人郁闷的是它还不能支持正则表达式. 先要说的是,这确实是门新语言,我在网站上有注释 a radar (rdar://17257306 for Apple folks). 如果你也认同这一观点,请支持. 我所说的正则表达式指的是这种(Ruby代码): if name =~ /ski$/ puts "#{name} is probably polish" end 如果要快速查询,可以使用=~操作符来返回匹配的结果.此外使用/pattern/syntax 形

  • swift 3.0 正则表达式查找/替换字符的实现代码

    1.什么是正则表达式 正则表达式,又称正规表示法.常规表示法(英语:Regular Expression,在代码中常简写为regex.regexp或RE),计算机科学的一个概念. 正则表达式使用单个字符串来描述.匹配一系列符合某个句法规则的字符串. 在很多文本编辑器里,正则表达式通常被用来检索.替换那些符合某个模式的文本. 2.正则表达式的字符组成 普通字符[a~z].特殊字符(称为"元字符") 3.支持 几乎所有的程序设计语言都支持正则表达式,例如:OC,swift,java,c#,

  • swift中自定义正则表达式运算符=~详解

    什么是正则表达式? 正则表达式,又称正规表示法.常规表示法(英语:Regular Expression,在代码中常简写为regex.regexp或RE),计算机科学的一个概念.正则表达式使用单个字符串来描述.匹配一系列符合某个句法规则的字符串.在很多文本编辑器里,正则表达式通常被用来检索.替换那些符合某个模式的文本. swift 至今并没有在语言层面上支持正则表达式,可能在开发app时正则表达式使用的场景并不多. 封装 在 Cocoa 中我们可以使用 NSRegularExpression 来做

  • swift中的正则表达式小结

    作为一门先进的编程语言,Swift 可以说吸收了众多其他先进语言的优点,但是有一点却是让人略微失望的,就是 Swift 至今为止并没有在语言层面上支持正则表达式. 正则表达式的用处: 判断给定的字符串是否符合某一种规则(专门用于操作字符串) - 电话号码,电子邮箱,URL... - 可以直接百度别人写好的正则 - 别人真的写好了,而且测试过了,我们可以直接用 - 要写出没有漏洞正则判断,需要大量的测试,通常最终结果非常负责 过滤筛选字符串,网络爬虫 替换文字,QQ聊天,图文混排 语法规则 使用过

  • 在Swift中如何使用正则表达式详解

    前言 正则表达式,又称规则表达式.(英语:Regular Expression,在代码中常简写为regex.regexp或RE),计算机科学的一个概念.正则表通常被用来检索.替换那些符合某个模式(规则)的文本. 正则表达式(Regular expression, regex)允许我们在几秒钟内在成千上万文档间进行复杂检索与替换,自从诞生50多年来它依旧广泛使用. Swift虽然是一个新出的语言,但却不提供专门的处理正则的语法和类.所以我们只能使用古老的NSRegularExpression类进行

  • IOS 开发之swift中手势的实例详解

    IOS 开发之swift中手势的实例详解 手势操作主要包括如下几类 手势 属性 说明 点击 UITapGestureRecognizer numberOfTapsRequired:点击的次数:numberOfTouchesRequired:点击时有手指数量 设置属性 numberOfTapsRequired 可以实现单击,或双击的效果 滑动 UISwipeGestureRecognizer direction:滑动方向 direction 滑动方向分为上Up.下Down.左Left.右Right

  • Swift中闭包实战案例详解

    前言 无论苹果的官方文档还是由官方文档衍生出来的一些文章和书籍都比较重视基础语法知识的讲解,对于实战中的应用提及的都很少,所以当我们想使用"闭包"解决一些问题的时候,会忽然出现看着一堆理论知识却不知从何下手的尴尬感,这就是理论和时实战的区别了. 本文不赘述Swift闭包的的基本语法了,百度或者Google下有很多资料.如题所示本文着重讲述Swift闭包的一些实战案例,有需要的小伙伴可以参考下,经验丰富的大神也请指教. 关于如何理解闭包 学习闭包的第一个难点就是理解闭包,可能很多人用了很

  • Swift中的指针操作详解

    前言 Objective-C和C语言经常需要使用到指针.Swift中的数据类型由于良好的设计,使其可以和基于指针的C语言API无缝混用.但是语法上有很大的差别. 默认情况下,Swift 是内存安全的,这意味着它禁止我们直接操作内存,并且确保所有的变量在使用前都已经被正确地初始化了.但是,Swift 也提供了我们使用指针直接操作内存的方法,直接操作内存是很危险的行为,很容易就出现错误,因此官方将直接操作内存称为 "unsafe 特性". 一旦我们开始直接操作内存,一切就得靠我们自己了,因

  • swift中的@UIApplicationMain示例详解

    前言 最近在学习swift,在学习中遇到了一些需要整理记录的知识点,下面本文主要介绍了关于swift中@UIApplicationMain的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 程序如何开始的 C 系列语言中,程序的入口都是 main 函数,一个 Objective-C 的 iOS app 项目在新建时,Xcode 会给我们创建好一个 main.m 的文件. #import <UIKit/UIKit.h> #import "AppDelegate

  • Swift中转义闭包示例详解

    目录 前言 转义与非转义闭包 逃离方法 将转义关闭付诸行动 注意强参考周期 内存泄漏背后的原因 消除强引用循环 概括 前言 Swift 是一种非常强大的编程语言,是为 Apple 生态系统开发应用程序的首选:iOS.macOS.watchOS 和 tvOS.作为使用 Swift 编写代码的开发人员,我们经常使用闭包:语言的一个重要而重要的章节. 闭包不是初学者开始的主题.然而,这是每个人都必须尽快了解的东西.有很多方面需要了解并了解它们的工作原理.在所有这些中,有一个特定的:转义闭包和@esca

  • php中字符串和正则表达式详解

    一.字符串类型的特点 1.PHP是弱类型语言,其他数据类型一般都可以直接应用于字符串函数操作. <?phpecho substr("123456",2,4);  //输出345echo substr(123456,2,4);    //输出345echo hello;                 //先查找hello常量,若没找到,将hello看做字符串使用?> 2.字符串可以作为"数组",是字符的集合. <?php$str = "w

  • Struts 2中的constant配置详解

    1.<constant name="struts.i18n.encoding" value="UTF-8" /> 指定Web应用的默认编码集,相当于调用 HttpServletRequest的setCharacterEncoding方法. 2.<constant name="struts.i18n.reload" value="false"/> 该属性设置是否每次HTTP请求到达时,系统都重新加载资源文

  • IOS Swift基础之switch用法详解

    IOS  Swift基础之switch用法详解 概述 Swift中的switch语句与Java等语言中的switch有很大的相似点,但是也有不同的地方,并且更加灵活. Swift中switch的case语句中不需要添加break Swift中需要考虑所有情况,default是必要的. case分支可以添加多个条件,用,分割 case不局限与常量,可以使使用范围 switch里可以使用元组 switch默认不需要添加break,执行一个case之后就跳出语句,如果想要继续下面的语句可以使用fall

  • python模块之re正则表达式详解

    一.简单介绍 正则表达式是一种小型的.高度专业化的编程语言,并不是python中特有的,是许多编程语言中基础而又重要的一部分.在python中,主要通过re模块来实现. 正则表达式模式被编译成一系列的字节码,然后由用c编写的匹配引擎执行.那么正则表达式通常有哪些使用场景呢? 比如为想要匹配的相应字符串集指定规则: 该字符串集可以是包含e-mail地址.Internet地址.电话号码,或是根据需求自定义的一些字符串集: 当然也可以去判断一个字符串集是否符合我们定义的匹配规则: 找到字符串中匹配该规

随机推荐