Swift2.0 - 正则表达式
什么是正则表达式?
正则表达式,又称正规表示法、常规表示法(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。在很多文本编辑器里,正则表达式通常被用来检索、替换那些符合某个模式的文本。
列目录时, dir *.txt或ls *.txt中的*.txt就不是一个正则表达式,因为这里*与正则式的*的含义是不同的。
构造正则表达式的方法和创建数学表达式的方法一样。也就是用多种元字符与运算符可以将小的表达式结合在一起来创建更大的表达式。正则表达式的组件可以是单个的字符、字符集合、字符范围、字符间的选择或者所有这些组件的任意组合。
正则表达式是由普通字符(例如字符 a 到 z)以及特殊字符(称为"元字符")组成的文字模式。模式描述在搜索文本时要匹配的一个或多个字符串。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。
正则表达式(开发):
在编写处理字符串的程序时,经常会有查找符合某些复杂规则的字符串的需要。正则表达式就是用于描述这些规则的工具。换句话说,正则表达式就是记录文本规则的代码
正则表达式是对字符串操作的一种逻辑公式,用事先定义好的一些特定字符、及这些特定字符的组合,组成一个"规则字符串",这个"规则字符串"用来表达对字符串的一种过滤逻辑。
- 几乎所有的程序设计语言都支持正则表达式,例如:OC,java,c#,python,js等
- 在很多文本编辑器里,可以使用正则表达式进行检索,Xcode同样支持正则表达式!
正则表达式的用处:
1. 判断给定的字符串是否符合某一种规则(专门用于操作字符串)
> 电话号码,电子邮箱,URL...
可以直接百度别人写好的正则
1> 别人真的写好了,而且测试过了,我们可以直接用
2> 要写出没有漏洞正则判断,需要大量的测试,通常最终结果非常负责
2. 过滤筛选字符串,网络爬虫
3. 替换文字,QQ聊天,图文混排
0> 匹配
--------------------------------------------------------------------------------
(pattern) 匹配pattern并获取这一匹配,所获取的匹配可以从产生的Matches集合得到
1> 集合
--------------------------------------------------------------------------------
[xyz] 字符集合(x/y或z)
[a-z] 字符范围
[a-zA-Z]
[^xyz] 负值字符集合 (任何字符, 除了xyz)
[^a-z] 负值字符范围
[a-d][m-p] 并集(a到d 或 m到p)
2> 常用元字符
--------------------------------------------------------------------------------
. 匹配除换行符以外的任意字符
\w 匹配字母或数字或下划线或汉字 [a-zA-Z_0-9]
\s 匹配任意的空白符(空格、TAB\t、回车\r \n)
\d 匹配数字 [0-9]
^ 匹配字符串的开始
$ 匹配字符串的结束
\b 匹配单词的开始或结束
2> 常用反义符
--------------------------------------------------------------------------------
\W 匹配任意不是字母,数字,下划线,汉字的字符[^\w]
\S 匹配任意不是空白符的字符 [^\s]
\D 匹配任意非数字的字符[^0-9]
\B 匹配不是单词开头或结束的位置
[^x] 匹配除了x以外的任意字符
[^aeiou] 匹配除了aeiou这几个字母以外的任意字符
4> 常用限定符
--------------------------------------------------------------------------------
* 重复零次或更多次
+ 重复一次或更多次
? 重复零次或一次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次,
5> 贪婪和懒惰
--------------------------------------------------------------------------------
*? 重复任意次,但尽可能少重复
*+ 重复1次或更多次,但尽可能少重复
?? 重复0次或1次,但尽可能少重复
{n,m}? 重复n到m次,但尽可能少重复
{n,}? 重复n次以上,但尽可能少重复
// 需求: 判断给定字符串中有没有QQ号码
*QQ规则:
-1.必须全部都是数字
-2.不能以0开头
-3.5~15位
常规判断
/*
* 第一个参数: 要匹配的字符串
* 第二个参数: 返回结果是否是QQ账号
*/
private func checkQQ1(str: String) -> Bool
{
// 1.判断是否以0开头
if str.hasPrefix("0")
{
return false
}
// 2.判断是否是5~15位
if str.characters.count < 5 || str.characters.count > 15
{
return false
}
// 3.判断是否全部都是数字
for c in str.characters
{
if c < "0" || c > "9"
{
return false
}
}
return true
}
############ pragrma- 写了那么多代码也只是判断出是否是QQ账号,并不能判断出具体什么才是QQ账号 ############
正则表达式的基本使用
/*
* 步骤:
* 1.创建规则
* 2.利用规则创建一个正则表达式对象
* 3.利用表达式对象取出结果,匹配符合规则的数据
*/
private func checkQQ2(str: String) -> String
{
// 1.创建规则
// [] 匹配一位
// {} 匹配多位
let pattern = "[1-9][0-9]{4,14}"
// 2.利用规则创建一个正则表达式对象
/*
* 第一个参数: 正则表达式的规则
* 第二个参数: 附加选项(是否忽略大小写等等)
*/
/**
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 指定单词边界
*/
let regex = try! NSRegularExpression(pattern: pattern, options: NSRegularExpressionOptions(rawValue: 0))
// 3.匹配符合规则的数据
// 从指定字符串中取出第一个匹配规则的字符串的范围,返回的是NSTextCheckingResult?类型
// let res = regex.firstMatchInString(str, options: NSMatchingOptions(rawValue: 0), range: NSMakeRange(0, str.characters.count))
// 从指定字符串中取出有多少个匹配规则的字符串,返回的是Int类型
// let res = regex.numberOfMatchesInString(str, options: NSMatchingOptions(rawValue: 0), range: NSMakeRange(0, str.characters.count))
// 从指定字符串中取出第一个匹配规则的字符串的范围,返回的是NSRange类型
// let res = regex.rangeOfFirstMatchInString(str, options: NSMatchingOptions(rawValue: 0), range: NSMakeRange(0, str.characters.count))
// 从指定字符串中取出所有匹配规则的字符串的结果集,返回的是[NSTextCheckingResult]类型
let resArray = regex.matchesInString(str, options: NSMatchingOptions(rawValue: 0), range: NSMakeRange(0, str.characters.count))
print(resArray)
return ""
}
正则表达式的练习
// ViewController.swift
// 正则表达式练习
//
// Created by ming on 16/04/16.
// Copyright © 2016年 ming. All rights reserved.
import UIKit
/**
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 指定单词边界
*/
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// 匹配手机号码
/*
1. 11位
2.必须以1开头
3.第二位必须是 3578
4.必须都是数字
*/
let str = "13554499311"
// 1.创建规则
let pattern = "1[3578]\\d{9}"
// 2.利用规则创建表达式对象
let regex = try! NSRegularExpression(pattern: pattern, options: NSRegularExpressionOptions(rawValue: 0))
// 3.利用表达式对象取出结果
let res = regex.firstMatchInString(str, options: NSMatchingOptions(rawValue: 0), range: NSMakeRange(0, str.characters.count))
print(res)
}
func test(){
let str = "123456789"
// 1.创建规则
// 看看字符串是否字母
// let pattern = "[a-zA-Z]"
// 看看字符串是否是数字
// let pattern = "[0-9]"
// let pattern = "[^a-zA-Z]"
// let pattern = "\\d"
// 看看字符串中有没有3个连在一起的数字
// let pattern = "\\d{3}"
// 看看字符串中有没有3个或3个以上连在一起的数字
// let pattern = "\\d{3,}"
// 看看字符串中有没有3~5个连在一起的数字
let pattern = "\\d{3,5}?"
// 2.利用规则创建表达式对象
let regex = try! NSRegularExpression(pattern: pattern, options: NSRegularExpressionOptions(rawValue: 0))
// 3.利用表达式对象取出结果
let res = regex.firstMatchInString(str, options: NSMatchingOptions(rawValue: 0), range: NSMakeRange(0, str.characters.count))
print(res)
}
}
-
自己开发用到过的常见正则表达式:
-
匹配手机号码:
"^((13[0-9])|(147)|(15[0-3,5-9])|(18[0,0-9])|(17[0-3,5-9]))\\d{8}$"
-
至少输入3至多输入15位:
"^[a-zA-Z0-9]{3,15}$" // 输入3-15位的正则表达式
-
正则匹配用户身份证号15或18位:
"(^[0-9]{15}$)|([0-9]{17}([0-9]|[0-9a-zA-Z])$)"
-
红包输入框的过滤:
"^[0-9]*?((.)[0-9]{0,2})?$" // 金额输入框,前面可以输入很多个0
-
"(^(0|([1-9]{0,}))([.]\\d{0,2})?)$" // 金额输入框,前面只能输入很一个0,但是开头是非0输入,后面不能输入0了,有BUG
"(^(0?|[1-9]\\d*?)([.]\\d{0,2})?)$" // 金额输入框,前面只能输入很一个0,但是开头是非0输入,后面可以输入0了
"(^(0??|[1-9]\\d{0,19})([.]\\d{0,2})?)$" // 金额输入框,前面只能输入很一个0,但是开头是非0输入,后面可以输入0了,可以限制输入的个数
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let regex = "(^(0|([1-9]{0,}))([.]\\d{0,2})?)$"
// "^[0-9]*?((.)[0-9]{0,2})?$"
// "(^(0|([1-9]{0,}))([.]\\d{0,2})?)$"
// "(^[1-9]\\d{0,}(([.]\\d{0,2})?))?|(^[0]?(([.]\\d{0,2})?))?"
// "([1-9]\\d{0,}(([.]\\d{0,1})?))?|([0]?(([.]\\d{0,1})?))?"
// "([1-9]\\d{0,}(([.]\\d{0,1})?))?|([0]|(0[.]\\d{0,1}))" // |
// "^[0-9]+(.[0-9]{2})?$" //"[0-9]+\\.?[0-9]{2}" //"^\\d+(\\.\\d{2})?$" // "/^(0|[-][1-9]d{0,}).d{1,2}$/" // "^(0|[1-9]\\d{0,})(([.]\\d{0,1})?)?$"
// 2.利用规则创建表达式对象
let predicate = NSPredicate(format: "SELF MATCHES %@", regex)
let text = (textField.text ?? "") + string
if text.hasPrefix(".") {
textField.text = "0" + textField.text!
}
print(predicate.evaluate(with: text))
return predicate.evaluate(with: text)
}
//准确来说这份代码
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { //
if string == "" { // 如果输入的是删除键
location = textField.text!.count-1
print(range.location)
print("location=\(location)")
return true
}
if textField.text!.count > 15 {
return false
}
location = textField.text!.count
if string == "." { // 如果输入的字符串是“.”,特殊,(因为只能保留小数点后2位)
if range.location < (location - 2) {
print(range.location)
print("location=\(location)")
return false
}else {
if range.location == 0 && string == "." { // 第一位为"."时,前面插入0
textField.text = "0" + textField.text!
}
}
}
let text = (textField.text ?? "") + string
let regex = "^[0-9]*?((.)[0-9]{0,2})?" // "(^(0??|[1-9]\\d{0,19})([.]\\d{0,2})?)$"
// 2.利用规则创建表达式对象
let predicate = NSPredicate(format: "SELF MATCHES %@", regex)
location = text.count
print(range.location)
print("location=\(location)")
if predicate.evaluate(with: text) {
return true
}else {
var isAllowInput = false
if (textField.text!.contains(".")) {
let locationDot = (textField.text! as NSString).range(of: ".").location
if range.location < locationDot + 1 {
isAllowInput = true
}
}
return isAllowInput
}
}