正则表达式
正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。
给定一个正则表达式和另一个字符串,我们可以达到如下的目的:
1. 给定的字符串是否符合正则表达式的过滤逻辑(称作“匹配”);
2. 可以通过正则表达式,从字符串中获取我们想要的特定部分(称作“切割”);
3. 如果regex中有定义组,可以在第二参数中通过$符号获取正则表达式中的已有的组(称作“替换”)。
java.util.regex
类 Pattern 正则表达式的编译表示形式。
static Pattern |
compile(String regex) 将给定的正则表达式编译到模式中。 |
static Pattern |
compile(String regex,
int flags) 将给定的正则表达式编译到具有给定标志的模式中。 |
int |
flags()
返回此模式的匹配标志。 |
Matcher |
matcher(CharSequence input)
创建匹配给定输入与此模式的匹配器。 |
static boolean |
matches(String regex, CharSequence input)
编译给定正则表达式并尝试将给定输入与其匹配。 |
String |
pattern()
返回在其中编译过此模式的正则表达式。 |
static String |
quote(String s)
返回指定 String 的字面值模式 String 。 |
String[] |
split(CharSequence input)
围绕此模式的匹配拆分给定输入序列。 |
String[] |
split(CharSequence input,
int limit) 围绕此模式的匹配拆分给定输入序列。 |
String |
toString()
返回此模式的字符串表示形式。 |
java.util.regex
类 Matcher 通过解释 Pattern
对character sequence
执行匹配操作的引擎。
Matcher |
appendReplacement(StringBuffer sb, String replacement) 实现非终端添加和替换步骤。 |
StringBuffer |
appendTail(StringBuffer sb)
实现终端添加和替换步骤。 |
int |
end()
返回最后匹配字符之后的偏移量。 |
int |
end(int group)
返回在以前的匹配操作期间,由给定组所捕获子序列的最后字符之后的偏移量。 |
boolean |
find()
尝试查找与该模式匹配的输入序列的下一个子序列。 |
boolean |
find(int start)
重置此匹配器,然后尝试查找匹配该模式、从指定索引开始的输入序列的下一个子序列。 |
String |
group()
返回由以前匹配操作所匹配的输入子序列。 |
String |
group(int group)
返回在以前匹配操作期间由给定组捕获的输入子序列。 |
int |
groupCount()
返回此匹配器模式中的捕获组数。 |
boolean |
hasAnchoringBounds()
查询此匹配器区域界限的定位。 |
boolean |
hasTransparentBounds()
查询此匹配器区域边界的透明度。 |
boolean |
hitEnd()
如果匹配器执行的最后匹配操作中搜索引擎遇到输入结尾,则返回 true。 |
boolean |
lookingAt()
尝试将从区域开头开始的输入序列与该模式匹配。 |
boolean |
matches()
尝试将整个区域与模式匹配。 |
Pattern |
pattern()
返回由此匹配器解释的模式。 |
static String |
quoteReplacement(String s)
返回指定 String 的字面值替换 String 。 |
Matcher |
region(int start,
int end) 设置此匹配器的区域限制。 |
int |
regionEnd()
报告此匹配器区域的结束索引(不包括)。 |
int |
regionStart()
报告此匹配器区域的开始索引。 |
String |
replaceAll(String replacement)
替换模式与给定替换字符串相匹配的输入序列的每个子序列。 |
String |
replaceFirst(String replacement)
替换模式与给定替换字符串匹配的输入序列的第一个子序列。 |
boolean |
requireEnd()
如果很多输入都可以将正匹配更改为负匹配,则返回 true。 |
Matcher |
reset()
重置匹配器。 |
Matcher |
reset(CharSequence input)
重置此具有新输入序列的匹配器。 |
int |
start()
返回以前匹配的初始索引。 |
int |
start(int group)
返回在以前的匹配操作期间,由给定组所捕获的子序列的初始索引。 |
MatchResult |
toMatchResult()
作为 MatchResult
返回此匹配器的匹配状态。 |
String |
toString()
返回匹配器的字符串表示形式。 |
Matcher |
useAnchoringBounds(boolean b)
设置匹配器区域界限的定位。 |
Matcher |
usePattern(Pattern newPattern)
更改此 Matcher 用于查找匹配项的 Pattern。 |
Matcher |
useTransparentBounds(boolean b)
设置此匹配器区域边界的透明度。 |
split切割
public String[] split(CharSequence input,
int limit)
- 围绕此模式的匹配拆分给定输入序列。
- 如果限制 n 大于零,那么模式至多应用 n> - 1 次,数组的长度不大于 n,并且数组的最后条目将包含除最后的匹配定界符之外的所有输入。如果 n 非正,那么将应用模式的次数不受限制,并且数组可以为任意长度。如果 n 为零,那么应用模式的次数不受限制,数组可以为任意长度,并且将丢弃尾部空字符串。
1 import java.util.regex.*; 2 import java.util.*; 3 class RegexDemo1 4 { 5 public static void main(String[] args) 6 { 7 splitDemo(); 8 } 9 public static void splitDemo() 10 { 11 String str = "zhangsan...lisi..wangwu....zhaoliu.."; 12 String reg = "\\.+"; 13 14 String[] arr1 = str.split(reg); 15 16 //String[] arr2 = str.split(reg,2); 17 //String[] arr3 = str.split(reg,0); 18 19 List<String> list = Arrays.asList(arr1); 20 System.out.println(list); 21 System.out.println(list.size()); 22 } 23 }
替换replace
1 class RegexDemo2 2 { 3 public static void main(String[] args) 4 { 5 replaceDemo("www13.bai51du2345.com678","\\d{1,}",""); 6 7 replaceDemo("affffgthjjjkhjllkeeu","(.)\\1+","@"); 8 9 //将叠词替换成$. //将重叠的字符替换成单个字母。ffff->f 10 replaceDemo("affffgthjjjkhjllkeeu","(.)\\1+","$1"); 11 } 12 public static void replaceDemo(String str,String regx,String newstr) 13 { 14 str =str.replaceAll(regx,newstr); 15 System.out.println(str); 16 } 17 }
取叠词:
可以将规则封装成一个组。用()完成。组的出现都有编号,从1开始, 想要使用已有的组可以通过 \n(n就是组的编号)的形式来获取。
String str ="sdggdfhhykjjk"
String reg = "(.)\\1";
result:
[sd, df, yk,k]
常用匹配格式
构造 | 匹配 |
---|---|
字符 | |
x | 字符 x |
\\ | 反斜线字符 |
\0n | 带有八进制值 0 的字符 n (0 <= n <= 7) |
\0nn | 带有八进制值 0 的字符 nn (0 <= n <= 7) |
\0mnn | 带有八进制值 0 的字符 mnn(0 <= m <= 3、0 <= n <= 7) |
\xhh | 带有十六进制值 0x 的字符 hh |
\uhhhh | 带有十六进制值 0x 的字符 hhhh |
\t | 制表符 ('\u0009') |
\n | 新行(换行)符 ('\u000A') |
\r | 回车符 ('\u000D') |
\f | 换页符 ('\u000C') |
\a | 报警 (bell) 符 ('\u0007') |
\e | 转义符 ('\u001B') |
\cx | 对应于 x 的控制符 |
字符类 | |
[abc] | a、b 或 c(简单类) |
[^abc] | 任何字符,除了 a、b 或 c(否定) |
[a-zA-Z] | a 到 z 或 A 到 Z,两头的字母包括在内(范围) |
[a-d[m-p]] | a 到 d 或 m 到 p:[a-dm-p](并集) |
[a-z&&[def]] | d、e 或 f(交集) |
[a-z&&[^bc]] | a 到 z,除了 b 和 c:[ad-z](减去) |
[a-z&&[^m-p]] | a 到 z,而非 m 到 p:[a-lq-z](减去) |
预定义字符类 | |
. | 任何字符(与行结束符可能匹配也可能不匹配) |
\d | 数字:[0-9] |
\D | 非数字: [^0-9] |
\s | 空白字符:[ \t\n\x0B\f\r] |
\S | 非空白字符:[^\s] |
\w | 单词字符:[a-zA-Z_0-9] |
\W | 非单词字符:[^\w] |
java.lang.Character 类(简单的 java 字符类型) | |
\p{javaLowerCase} | 等效于 java.lang.Character.isLowerCase() |
\p{javaUpperCase} | 等效于 java.lang.Character.isUpperCase() |
\p{javaWhitespace} | 等效于 java.lang.Character.isWhitespace() |
\p{javaMirrored} | 等效于 java.lang.Character.isMirrored() |
边界匹配器 | |
^ | 行的开头 |
$ | 行的结尾 |
\b | 单词边界 |
\B | 非单词边界 |
\A | 输入的开头 |
\G | 上一个匹配的结尾 |
\Z | 输入的结尾,仅用于最后的结束符(如果有的话) |
\z | 输入的结尾 |
Greedy 数量词 | |
X? | X,一次或一次也没有 |
X* | X,零次或多次 |
X+ | X,一次或多次 |
X{n} | X,恰好 n 次 |
X{n,} | X,至少 n 次 |
X{n,m} | X,至少 n 次,但是不超过 m 次 |
Reluctant 数量词 | |
X?? | X,一次或一次也没有 |
X*? | X,零次或多次 |
X+? | X,一次或多次 |
X{n}? | X,恰好 n 次 |
X{n,}? | X,至少 n 次 |
X{n,m}? | X,至少 n 次,但是不超过 m 次 |
Possessive 数量词 | |
X?+ | X,一次或一次也没有 |
X*+ | X,零次或多次 |
X++ | X,一次或多次 |
X{n}+ | X,恰好 n 次 |
X{n,}+ | X,至少 n 次 |
X{n,m}+ | X,至少 n 次,但是不超过 m 次 |
数量词有Greedy (贪婪)、Reluctant(懒惰)和Possessive(强占)三种:
- Greedy是最常用的,它的匹配方式是先把整个字符串吞下,然后匹配整个字符串,如果不匹配,就从右端吐出一个字符,再进行匹配,直到找到匹配或把整个字符串吐完为止。因为总是从最大匹配开始匹配,故称贪婪。
- Reluctant正好和Greedy相反,它先从最小匹配开始,先从左端吞入一个字符,然后进行匹配,若不匹配就再吞入一个字符,直到找到匹配或将整个字符串吞入为止。 因为总是从最小匹配开始,故称懒惰。
- Possessive和Greedy的匹配方式一样,先把整个字符串吞下,然后匹配整个字符串,如果匹配,就认为匹配,如果不匹配,就认为整个字符串不匹配,它不会从右端吐出一个字符串再进行匹配,只进行一次,故称强占。
数量词的区别以及字符串的获取
1 import java.util.regex.*; 2 class RegexDemo1 3 { 4 public static void main(String[] args) 5 { 6 method(); 7 } 8 public static void method() { 9 10 Pattern gp = Pattern.compile("1.+a"); //Greedy方式 11 Pattern rp = Pattern.compile("1.+?a"); //Reluctant方式 12 Pattern pp = Pattern.compile("1.++a"); //Possessive方式 13 Matcher gm = gp.matcher("12a34abc"); //Greedy匹配器 14 Matcher rm = rp.matcher("12a34abc"); //Reluctant匹配器 15 Matcher pm = pp.matcher("12a34abc"); //Possessive匹配器 16 17 if(gm.find()){ 18 System.out.println("Greedy方式----->"+gm.group()); 19 }else{ 20 System.out.println("Greedy方式找不到匹配值"); 21 } 22 23 if(rm.find()){ 24 System.out.println("Reluctant方式----->"+rm.group()); 25 }else{ 26 System.out.println("Reluctant方式找不到匹配值"); 27 } 28 29 if(pm.find()){ 30 System.out.println("Possessive方式----->"+pm.group()); 31 }else{ 32 System.out.println("Possessive方式找不到匹配值"); 33 } 34 } 35 } 36 ---------- 运行 ---------- 37 Greedy方式----->12a34a 38 Reluctant方式----->12a 39 Possessive方式找不到匹配值 40 41 输出完成 (耗时 0 秒) - 正常终止
练习
192.68.1.254 102.49.23.013 10.10.10.10 2.2.2.2 8.109.90.30将ip地址进行地址段顺序的排序。
还按照字符串自然顺序,只要让它们每一段都是3位即可。
1,按照每一段需要的最多的0进行补齐,那么每一段就会至少保证有3位。
2,将每一段只保留3位。这样,所有的ip地址都是每一段3位。
1 import java.util.regex.*; 2 import java.util.*; 3 class RegexDemo3 4 { 5 public static void main(String[] args) 6 { 7 ipDemo(); 8 } 9 public static void ipDemo() 10 { 11 String ip = "192.68.1.254 102.49.23.013 10.10.10.10 2.2.2.2 8.109.90.30"; 12 13 ip = ip.replaceAll("(\\d+)","00$1"); 14 System.out.println(ip); 15 16 ip = ip.replaceAll("0*(\\d{3})","$1"); 17 System.out.println(ip); 18 19 String[] arr = ip.split(" "); 20 Arrays.sort(arr); 21 22 for(String s : arr) 23 { 24 System.out.println(s.replaceAll("0*(\\d+)","$1")); 25 } 26 } 27 }