正则学习
[TOC]
元字符:
^ $ . [ ] { } - ? * + ( ) | \原义字符:除元字符外,其他所有字符都被认为是原义字符。个别情况下\会被用来创建元序列,元字符也可以被转义为原义字符。
元字符
1. 任何字符(.)
被用来匹配
任意字符,在正则表达式中包含它,它将会匹配在此位置的任意一个字符。(除\n``\r之外)
eg:
- '.123' -> 表示匹配项至少 4 个字符,其中匹配的字符中至少有'123'三个连贯字符,并且'123'前面需要有一个任意字符。
- '..123' -> 表示匹配项至少 5 个字符,其中匹配的字符中至少有'123'三个连贯字符,并且'123'前面需要有两个任意字符。
2. 锚点(^ & $)
在正则表达式中,插入
^和$被看作是锚点,表示以什么开头和以什么结尾。 当^在元字符[]中时,表示的是取反
eg:
- '^123' -> 以'123'开头的内容
- '123$' -> 以'123'结尾的内容
- '^123&' -> 匹配'123'字符串
- '^..j.r$' -> 表示字符长度为
5,任意字符开头,第3个字符为j, 第5个字符为r,并且以r字符结尾 - '[^bg]123' -> 表示'123'字符前面有一个除了
b和g之外的任意字符
3. 中括号表达式和字符类([])
除了
给定位置匹配任意字符外,通过中括号表达式可以从一个给定的字符集合中匹配单个字符
eg:
- '[bg]123' -> 表示'123'字符前的一个字符只能是
b或g
一个
字符集合可以包含任意多个字符,并且元字符在[]中会失去它们的特殊含义。但是,^和-在[]中有另外的含义。^:表示否定-:表示一个字符范围,传统范围为'[0123456789]',使用-为'[0-9]'
eg:
- '[^bg]123' -> 表示'123'字符前面有一个除了
b和g之外的任意字符 - '[0-9]123' -> 表示'123'字符前面有一个
0123456789中的任意一个字符
3.1 POSIX 字符集
不同的系统,可能'[A-Z]'表示的字符集不同。 为了部分的解决这个问题,
posix标准引入了locale概念,它能针对不同地区选择合适的字符集。
| 字符集 | 说明 | |
|---|---|---|
| [:alnum:] | 字母数字字符。在 ASCII 中,等价于:[A-Za-z0-9] | |
| [:word:] | 与[:alnum:]相同, 但增加了下划线字符。 | |
| [:alpha:] | 字母字符。在 ASCII 中,等价于:[A-Za-z] | |
| [:blank:] | 包含空格和 tab 字符。 | |
| [:cntrl:] | ASCII 的控制码。包含了0到31,和127的 ASCII 字符。 | |
| [:digit:] | 数字0到9 | |
| [:graph:] | 可视字符。在 ASCII 中,它包含33到126的字符。 | |
| [:lower:] | 小写字母。 | |
| [:punct:] | 标点符号字符。在 ASCII 中,等价于:[-!”#$%&'()*+,./:;<=>?@[\]_`{ | }~] |
| [:print:] | 可打印的字符。在[:graph:]中的所有字符,再加上空格字符。 | |
| [:space:] | 空白字符,包括空格、tab、回车、换行、vertical tab 和 form feed.在 ASCII 中, 等价于:[ \t\r\n\v\f] | |
| [:upper:] | 大写字母。 | |
| [:xdigit:] | 用来表示十六进制数字的字符。在 ASCII 中,等价于:[0-9A-Fa-f] |
eg:
- '^[[:digit:]]123' -> 表示以
数字0到9开头,后面跟着'123'
4. 交替,或操作(|)
允许从一系列表达式之间选择匹配项,就像
[]允许从一系列指定字符之间匹配单个字符。|允许从一系列字符串或者其它的正则表达式中选择匹配项。和符号或语义有点相通。
eg:
- '^(bz|gz|zip)' -> 表示匹配以'bz'或'gz'或'zip'开头的字符内容
5. ? - 匹配0个或者1个元素
表示一个可选的字符。使前面的元素可有可无
eg:
- '^1e?23$' -> 表示以'1'开头,'23'结尾,中间有或者没有'e'
6. * - 匹配0个或者多个元素
和
?一样,表示一个可选的字符,但是?匹配的字符只可以出现一次,而*匹配的字符可以出现任意次
eg:
- '^1(3|5)*.$' -> 表示以'1'开头,
任意字符结尾,中间可以有无数(或者0)个'3'或'5'
7. + - 匹配1个或者多个元素
和
*类似,但是它要求前面至少出现一次匹配的元素
eg:
- '^1(3|5)+.$' -> 表示以'1'开头,
任意字符结尾,中间至少有1个'3'或'5'
在*和+后面添加?可以实现最小匹配。 eg: 使用'<.*?>' 匹配'<h1>test</h1>'时,如果没有?则匹配整个字符串,如果有?则只匹配最前面的'<h1>'
8. {} - 匹配特定个数的元素
{}备用来表示要求匹配的最小和最大数目,他们通过4种方法来指定
| 限定符 | 意思 |
|---|---|
| {n} | 前面的元素出现了 n 次(前面的元素== n) |
| {n,m} | 前面的元素至少出现了n次,小于等于m次(n<=前面的元素<=m) |
| {,m} | 前面的元素出现了不多于m次(前面的元素<=m)(在iOS中需写成{0,m},其他语言未知) |
| {n,} | 前面的元素至少出现了n次(前面的元素>=n) |
eg:
- '^1(3|5){4}.$' -> 表示以'1'开头,
任意字符结尾,中间有4个'3'或'5' - '^1(3|5){4,6}.$' -> 表示以'1'开头,
任意字符结尾,中间有4到6个'3'或'5' - '^1(3|5){,4}.'**
- '^1(3|5){4,}.$' -> 表示以'1'开头,
任意字符结尾,中间有4个及以上个'3'或'5'
9. 定位符(\b & \B & ^ & $)
^和$同第二点-锚点\b:匹配单词边界处。\B:\b的反义,匹配单词的非边界处。\b或\B,放在字符前面表示开头,如'\bst','\Bst',放在字符后面表示结尾,比如'st\b','st\B'
eg:
- '\bst' -> 表示语句中单词以'st'开头的部分,用其匹配 'studyst tests stdy',并将满足条件的部分替换成'#',将得到'#udyst tests #dy',其中'#udy
sttests #dy'亮色部分不变。 - 'st\b' -> 表示语句中单词以'st'结尾的部分,用其匹配 'studyst tests stdy',并将满足条件的部分替换成'#',将得到'study# tests stdy',其中'
study# testsstdy'亮色部分不变。 - '\Bst' -> 表示语句中单词不以'st'开头的部分,用其匹配 'studyst tests stdy' ,并将满足条件的'st'替换成'#',将得到'study# te#s stdy',其中'
study# te#sstdy'亮色部分不变。 - 'st\B' -> 表示语句中单词不以'st'结尾的部分,用其匹配 'studyst tests stdy' ,并将满足条件的'st'替换成'#',将得到'#udyst te#s #dy',其中'#udy
stte#s #dy'亮色部分不变。
普通字符
普通字符包括没有显式指定为元字符的所有可打印和不可打印字符。这包括所有大写和小写字母、所有数字、所有标点符号和一些其他符号。
\s与\S
\s:匹配所有空白符号包括换行符 \S:匹配非空字符,不包括换行符
eg:
- '^.111[\s]$':表示以
任意字符开头,中间 3 个'1',以空字符串' '、'\n'或'\r'结尾。 - '^.111[\s]$':表示以
任意字符开头,中间 3 个'1',以空字符串' '、'\n'或'\r'以外的字符结尾。 - '^.111[\s\S]$':表示以
任意字符开头,中间 3 个'1',以任意字符结尾,包括空字符串' '和'\n'。
\w
匹配字母、数字、下划线。等价于
[A-Za-z0-9_]
非打印字符
| 字符 | 描述 |
|---|---|
| \cx | 匹配由x指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 'c' 字符。 |
| \f | 匹配一个换页符。等价于 \x0c 和 \cL。 |
| \n | 匹配一个换行符。等价于 \x0a 和 \cJ。 |
| \r | 匹配一个回车符。等价于 \x0d 和 \cM。 |
| \s | 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。注意 Unicode 正则表达式会匹配全角空格符。 |
| \S | 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。 |
| \t | 匹配一个制表符。等价于 \x09 和 \cI。 |
| \v | 匹配一个垂直制表符。等价于 \x0b 和 \cK。 |
常见的简写形式
| 正则表达式 | 匹配区间 | 记忆方式 |
|---|---|---|
| \d | [0-9]表示是一位数字 | 其英文是digit(数字) |
| \D | [^0-9]表示除数字外的任意字符 | |
| \w | [0-9a-zA-Z_]表示数字、大小写字母和下划线 | w是word的简写,也称单词字符 |
| \W | [^0-9a-zA-Z_] | 非单词字符 |
| \s | [ \t\v\n\r\f]表示空白符,包括空格、水平制表符、垂直制表符、换行符、回车符、换页符 | s是space character的首字母 |
| \S | [^ \t\v\n\r\f] | 非空白符 |
| . | [^\n\r\u2028\u2029]通配符,表示几乎任意字符。换行符、回车符、行分隔符和段分隔符除外 |
正则查询
以 iOS 中的方法为例
/// 正则匹配
///
/// - Parameters:
/// - regex: 匹配规则
/// - validateString: 匹配对test象
/// - Returns: 返回结果
func RegularExpression(regex:String,validateString:String) -> [String]{
do {
let regex: NSRegularExpression = try NSRegularExpression(pattern: regex, options: [])
let matches = regex.matches(in: validateString, options: [], range: NSMakeRange(0, validateString.count))
var data:[String] = Array()
for item in matches {
let string = (validateString as NSString).substring(with: item.range)
data.append(string)
}
return data
}
catch {
return []
}
}
/// 字符串的替换
///
/// - Parameters:
/// - validateString: 匹配对象
/// - regex: 匹配规则
/// - content: 替换内容
/// - Returns: 结果
func replace(validateString:String,regex:String,content:String) -> String {
do {
let RE = try NSRegularExpression(pattern: regex, options: .caseInsensitive)
let modified = RE.stringByReplacingMatches(in: validateString, options: .reportProgress, range: NSRange(location: 0, length: validateString.count), withTemplate: content)
return modified
}
catch {
return validateString
}
}
选择 () ?= ?<= ?! ?<!
() 表示捕获分组
?=
exp1(?=exp2): 查找 exp2 前面的 exp1
eg:
- 使用 'test(?=[\d+])' 匹配字符串 '1234test12test122test', 得到的只有前面2个'test',最后一个'test'无法匹配时因为后面没有满足'[\d+]'条件
?<=
(?<=exp2)exp1:查找 exp2 后面的 exp1
eg: 使用 '(?<=[\d+])test' 匹配字符串 'test1234test12test122test', 可以得到后面 3 个'test',第一个'test'无法匹配时因为后面没有满足'[\d+]'条件。 [\d+]不知道为什么不能使用[0-9]+这种格式
?!
exp1(?!exp2):查找后面不是 exp2 的 exp1
eg: 使用 'test(?![0-9]+)' 匹配字符串 '1234test-12test122test',可以得到第 1 和 3 个'test',第 2 个'test'因为后面是数字,所以不满足。
?<!
(?<!exp2)exp1:查找前面不是 exp2 的 exp1
eg: 使用 '(?<![\d+])test' 匹配字符串 '1234test12test122-test',可以得到第 3 个'test',第 1 和 2 个'test',因为前面是数字,所以无法满足要求。[\d+]不知道为什么不能使用[0-9]+这种格式
** 反向引用 **
在正则表达式本身中引用之前出现的分组,即
反向引用。
eg: 比如要写一个正则支持匹配如下三种日期格式:
- 2016-06-12
- 2016/06/12
- 2016.06.12
如果使用 '\d{4}(-|/|.)\d{2}(-|/|.)\d{2}' 正则去匹配,则会导致 '2016-06/12' 也匹配成功,和要求不符。
如果我们要求分割符前后一致的话,就可以使用反向引用:
即正则表达式为:'\d{4}(-|/|.)\d{2}\1\d{2}',其中\1,表示引用之前的分组(-|\/|\.)。 同理,\2,\3分别表示第二个分组和第三个分组