Java笔记之正则表达式

本笔记来自 计算机程序的思维逻辑 系列文章

语法

单个字符

  • 特殊字符 \t \n \r
  • 八进制 \0
  • 十六进制 \x
  • Unicode编码字符 \u
  • 斜杠 \\
  • 元字符 . * + () ? $ [] - | 匹配其本身,需要加转义字符

字符组

任意字符

点号字符 . ,是元字符,默认模式下,它匹配除了换行符以外的任意字符

指定的多个字符之一

中括号 [] ,匹配组中的任意一个字符

字符区间

字符组 [] 中使用连字符 - ,表示连续的多个字符

排除型字符组

在字符组的最前面加字符 ^

字符组内的元字符

在字符组中,除了-^[]\外,其它元字符不再具备特殊含义

字符组运算

多个字符组等同于并集,使用&&表示交集

比如 [[abc][def]] ,等同于 [abcdef]

比如 [a-z&&[^de]] ,匹配除了de外,a-z的字符

预定义的字符组
  • \d 匹配一个数字字符,等同于[0-9]
  • \w 匹配一个单词字符,等同于[a-zA-Z0-9]
  • \s 匹配一个空白字符,等同于[\t\n\x0B\f\r]
  • \D 匹配一个非数字字符,即[^\d]
  • \W 匹配一个非单词字符,即[^\w]
  • \S 匹配一个非空白字符,即[^\s]
POSIX字符组
  • \p{Lower} 小写字母,等同于[a-z]
  • \p{Upper} 大写字母,等同于[A-Z]
  • \p{Digit} 数字,等同于[0-9]
  • \p{Punct} 标点符号,匹配!"#$%&'()*+,-./:;<=>?@[\]^_\``{|}~中的一个

量词

常用量词
  • + 表示前面字符出现一次或多次

    比如 ab+c ,匹配 abc abbc

  • * 表示前面字符出现零次或多次

    比如 ab*c ,匹配 ac abc abbbc

  • ? 表示前面字符可能出现,也可能不出现

    比如 ab?c ,匹配 acabc

通用量词

语法 {m,n} ,出现次数从 mn ,包括 mn

如果 n 没有限制,可以省略

如果两者一样,可以写成 {m}

比如 goo{1,}gle ,匹配 google goooogle gooooooogle

贪婪与懒惰

关于量词,它们的默认匹配是贪婪的

比如使用正则表达式 .*,处理字符串 firstsecond
本来想得到2个匹配:firstsecond
但默认情况下只得到一个匹配,匹配所有内容
如果希望在碰到第一个匹配时就停止,应该使用懒惰量词,在量词后面加上符号 ?
.*?

分组

表达式可以用括号()括起来,表示一个分组,分组可以嵌套

捕获分组

分组默认都有一个编号,按照括号的出现顺序,从 1 开始,从左到右依次递增

比如 a(bc)((de)(fg))
分组0是整个字符串,分组1是bc,分组2是defg,分组3是de,分组4是fg

分组量词

可以对分组使用量词,表示分组的出现次数

比如 a(bc)+d ,表示 bc 出现一次或多次

分组多选

括号()和元字符|一起,可以表示匹配其中的一个子表达式

比如 (http|ftp|file) ,匹配 httpftpfile

回溯引用

可以用斜杠\加分组编号引用之前匹配的分组

比如 <(\w+)>(.*) ,匹配 Home

命名分组

命名语法 (?X),引用语法 \k

比如 <(?\w+)>(.*)> 匹配 Home

非捕获分组

语法 (?:...) ,表示分组后续不需要被引用,提高性能

比如 (?:abc|def)

匹配模式

  • (?s) 单行模式
  • (?m) 多行模式
  • (?i) 不区分大小写模式

特殊边界

  • ^ 匹配整个字符串的开始;多行模式下,匹配行的开始

    比如 ^abc ,表示整个字符串必须以 abc 开始

  • $ 匹配整个字符串的结束;多行模式下,匹配行的结束

    比如 abc$ ,表示整个字符串必须以 abc 结束

  • \A 不管任何模式,总是匹配整个字符串的开始边界

  • \Z 不管任何模式,总是匹配整个字符串,换行符之前的结束边界

  • \z 不管任何模式,总是匹配整个字符串的结束边界

  • \b 匹配单词边界

环视边界匹配

环视不是分组,不占用分组编号,也称为 断言

  • 肯定顺序环视 (?=...)

    要求右边的字符串匹配指定的表达式

  • 否定顺序环视 (?!...)

    要求右边的字符串不能匹配指定的表达式

  • 肯定逆序环视 (?<=...)

    要求左边的字符串匹配指定的表达式

  • 否定逆序环视 (?

    要求左边的字符串不能匹配指定的表达式

强制转义

语法 \Q...\E\Q\E 之间的所有字符都会被视为普通字符

转义符

\ 是一个元字符,要在正则表达式中表示其本身,需要使用它转义,即\\

在Java中,使用字符串表示正则表达式,而在字符串中,\也是一个元字符,也就需要使用两个\来表示,即\\,如果要匹配其本身,则需要使用四个\,即\\\\

Java API

Pattern

字符串表示的正则表达式可以被编译为一个Pattern对象

编译有一定的成本,而且Pattern对象只与正则表达式有关,与要处理的具体文本无关吗,它可以安全地被多线程共享,所以,在使用同一个正则表达式处理多个文本时,应该尽量重用同一个Pattern对象,避免重复编译

匹配模式
  • Pattern.DOTALL 单行模式

  • Pattern.MULTILINE 多行模式

  • Pattern.CASE_INSENSITIVE 不区分大小写模式

  • Pattern.LITERAL 将其中的元字符看作普通字符

    static String quote(String s) 目的类似,将 s 中的字符都看作普通字符

切分

字符串中的 String[] split(String regex) 方法

split将参数regex看作正则表达式,而不是普通的字符,如果分隔符是元字符,就需要转义

split的额外参数limit,用于限定切分的数目

split 区别
  • Pattern接受的参数是CharSequence,更为通用
  • 如果regex长度大于1或包含元字符,Stringsplit方法会先将regex编译为Pattern对象,再调用Pattern对象的split方法,这时,为避免重复编译,应该优先采用Pattern的方法
  • 如果regex就是一个字符且不是元字符,Stringsplit方法会采用更为简单高效的实现,这时,应该优先采用String的方法
验证

字符串中的 boolean matches(String regex) 方法

实际调用Pattern的静态方法 static boolean matches(String regex, CharSequence input)

实际过程:先将regex编译成Pettern对象,再调用Patternmatcher方法生成一个Matcher对象,最后调用Matchermatches方法,判断是否完整匹配

Matcher

查找
  • boolean find() 遍历
  • String group() 匹配到的完整字符串
  • int start() 子字符串在整个字符串中的起始位置
  • int end() 子字符串在整个字符串中的结束位置加 1
  • int groupCount() 返回分组个数
  • String group(int group) 分组编号为 group 的内容
  • String group(String name) 分组命名为 name 的内容
  • int start(int group) 分组编号为 group 的起始位置
  • int end(int group) 分组编号为 group 的结束位置加 1
替换

字符串中的方法

  • String replace(char oldChar, char newChar)
  • String replace(CharSequence target, CharSequence replacement)
  • String replaceAll(String regex, String replacement)
  • String replaceFirst(String regex, String replacement)

后3个方法实际调用Patterncompile matcher方法和MatcherreplaceAll replaceFirst方法

边查找边替换
  • Matcher appendReplacement(StringBuffer sb, String replacement) 将匹配到的子字符串替换成 replacement 后追加到 sb 后,并更新最后追加位置
  • StringBuffer appendTail(StringBuffer sb) 将最后追加位置之后的子字符串追加到 sb

你可能感兴趣的:(Java笔记之正则表达式)