正则表达式(regular expression)描述了一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某个条件的子串等。
构造正则表达式的方法和创建数学表达式的方法一样。也就是用多种元字符与运算符可以将小的表达式结合在一起来创建更大的表达式。正则表达式的组件可以是单个的字符、字符集合、字符范围、字符间的选择或者所有这些组件的任意组合。
正则表达式是由普通字符(例如字符 a 到 z)以及特殊字符(称为"元字符")组成的文字模式。模式描述在搜索文本时要匹配的一个或多个字符串。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。
正则表达式的匹配规则是从左到右按规则匹配。我们首先来看如何使用正则表达式来做精确匹配。
对于正则表达式abc来说,它只能精确地匹配字符串"abc",不能匹配"ab","Abc","abcd"等其他任何字符串。
如果正则表达式有特殊字符,那就需要用\转义。例如,正则表达式a&c,其中&是用来匹配特殊字符&的,它能精确匹配字符串"a&c",但不能匹配"ac"、"a-c"、"a&&c"等。
要注意正则表达式在Java代码中也是一个字符串,所以,对于正则表达式a&c来说,对应的Java字符串是"a\&c",因为\也是Java字符串的转义字符,两个\实际上表示的是一个\:
// regex
public class Main {
public static void main(String[] args) {
String re1 = "abc";
System.out.println("abc".matches(re1));
System.out.println("Abc".matches(re1));
System.out.println("abcd".matches(re1));
String re2 = "a\\&c"; // 对应的正则是a\&c
System.out.println("a&c".matches(re2));
System.out.println("a-c".matches(re2));
System.out.println("a&&c".matches(re2));
}
}
如果想匹配非ASCII字符,例如中文,那就用\u####的十六进制表示,例如:a\u548cc匹配字符串"a和c",中文字符和的Unicode编码是548c。
匹配任意字符
精确匹配实际上用处不大,因为我们直接用String.equals()就可以做到。大多数情况下,我们想要的匹配规则更多的是模糊匹配。我们可以用.匹配一个任意字符。
例如,正则表达式a.c中间的.可以匹配一个任意字符,例如,下面的字符串都可以被匹配:
"abc",因为.可以匹配字符b;
"a&c",因为.可以匹配字符&;
"acc",因为.可以匹配字符c。
但它不能匹配"ac"、"a&&c",因为.匹配一个字符且仅限一个字符。
匹配数字
用.可以匹配任意字符,这个口子开得有点大。如果我们只想匹配0~9这样的数字,可以用\d匹配。例如,正则表达式00\d可以匹配:
"007",因为\d可以匹配字符7;
"008",因为\d可以匹配字符8。
它不能匹配"00A","0077",因为\d仅限单个数字字符。
匹配常用字符
用\w可以匹配一个字母、数字或下划线,w的意思是word。例如,java\w可以匹配:
"javac",因为\w可以匹配英文字符c;
"java9",因为\w可以匹配数字字符9;。
"java_",因为\w可以匹配下划线_。
它不能匹配"java#","java ",因为\w不能匹配#、空格等字符。
匹配空格字符
用\s可以匹配一个空格字符,注意空格字符不但包括空格,还包括tab字符(在Java中用\t表示)。例如,a\sc可以匹配:
"a c",因为\s可以匹配空格字符;
"a c",因为\s可以匹配tab字符\t。
它不能匹配"ac","abc"等。
匹配非数字
用\d可以匹配一个数字,而\D则匹配一个非数字。例如,00\D可以匹配:
"00A",因为\D可以匹配非数字字符A;
"00#",因为\D可以匹配非数字字符#。
00\d可以匹配的字符串"007","008"等,00\D是不能匹配的。
类似的,\W可以匹配\w不能匹配的字符,\S可以匹配\s不能匹配的字符,这几个正好是反着来的。
// regex
public class Main {
public static void main(String[] args) {
String re1 = "java\d"; // 对应的正则是java\d
System.out.println("java9".matches(re1));
System.out.println("java10".matches(re1));
System.out.println("javac".matches(re1));
String re2 = "java\\D";
System.out.println("javax".matches(re2));
System.out.println("java#".matches(re2));
System.out.println("java5".matches(re2));
}
}
重复匹配
我们用\d可以匹配一个数字,例如,A\d可以匹配"A0","A1",如果要匹配多个数字,比如"A380",怎么办?
修饰符可以匹配任意个字符,包括0个字符。我们用A\d可以匹配:
A:因为\d可以匹配0个数字;
A0:因为\d可以匹配1个数字0;
A380:因为\d*可以匹配多个数字380。
修饰符+可以匹配至少一个字符。我们用A\d+可以匹配:
A0:因为\d+可以匹配1个数字0;
A380:因为\d+可以匹配多个数字380。
但它无法匹配"A",因为修饰符+要求至少一个字符。
修饰符?可以匹配0个或一个字符。我们用A\d?可以匹配:
A:因为\d?可以匹配0个数字;
A0:因为\d?可以匹配1个数字0。
但它无法匹配"A33",因为修饰符?超过1个字符就不能匹配了。
如果我们想精确指定n个字符怎么办?用修饰符{n}就可以。A\d{3}可以精确匹配:
A380:因为\d{3}可以匹配3个数字380。
如果我们想指定匹配n~m个字符怎么办?用修饰符{n,m}就可以。A\d{3,5}可以精确匹配:
A380:因为\d{3,5}可以匹配3个数字380;
A3800:因为\d{3,5}可以匹配4个数字3800;
A38000:因为\d{3,5}可以匹配5个数字38000。
如果没有上限,那么修饰符{n,}就可以匹配至少n个字符。
分割字符串
使用正则表达式分割字符串可以实现更加灵活的功能。String.split()方法传入的正是正则表达式。我们来看下面的代码:
"a b c".split("\s"); // { "a", "b", "c" }
"a b c".split("\s"); // { "a", "b", "", "c" }
"a, b ;; c".split("[\,\;\s]+"); // { "a", "b", "c" }
如果我们想让用户输入一组标签,然后把标签提取出来,因为用户的输入往往是不规范的,这时,使用合适的正则表达式,就可以消除多个空格、混合,和;这些不规范的输入,直接提取出规范的字符串。
搜索字符串
使用正则表达式还可以搜索字符串,我们来看例子:
import java.util.regex.*;
public class Main {
public static void main(String[] args) {
String s = "the quick brown fox jumps over the lazy dog.";
Pattern p = Pattern.compile("\wo\w");
Matcher m = p.matcher(s);
while (m.find()) {
String sub = s.substring(m.start(), m.end());
System.out.println(sub);
}
}
}
我们获取到Matcher对象后,不需要调用matches()方法(因为匹配整个串肯定返回false),而是反复调用find()方法,在整个串中搜索能匹配上\wo\w规则的子串,并打印出来。这种方式比String.indexOf()要灵活得多,因为我们搜索的规则是3个字符:中间必须是o,前后两个必须是字符[A-Za-z0-9_]。
替换字符串
使用正则表达式替换字符串可以直接调用String.replaceAll(),它的第一个参数是正则表达式,第二个参数是待替换的字符串。我们还是来看例子:
// regex
public class Main {
public static void main(String[] args) {
String s = "The quick\t\t brown fox jumps over the lazy dog.";
String r = s.replaceAll("\s+", " ");
System.out.println(r); // "The quick brown fox jumps over the lazy dog."
}
}
上面的代码把不规范的连续空格分隔的句子变成了规范的句子。可见,灵活使用正则表达式可以大大降低代码量。
反向引用
如果我们要把搜索到的指定字符串按规则替换,比如前后各加一个xxxx,这个时候,使用replaceAll()的时候,我们传入的第二个参数可以使用$1、$2来反向引用匹配到的子串。例如:
// regex
public class Main {
public static void main(String[] args) {
String s = "the quick brown fox jumps over the lazy dog.";
String r = s.replaceAll("\s([a-z]{4})\s", " $1 ");
System.out.println(r);
}
}
上述代码的运行结果是:
the quick brown fox jumps over the lazy dog.
它实际上把任何4字符单词的前后用xxxx括起来。实现替换的关键就在于" $1 ",它用匹配的分组子串([a-z]{4})替换了$1。
练习
模板引擎是指,定义一个字符串作为模板:
Hello, ${name}! You are learning ${lang}!
其中,以${key}表示的是变量,也就是将要被替换的内容
当传入一个Map<String, String>给模板后,需要把对应的key替换为Map的value。
例如,传入Map为:
{
"name": "Bob",
"lang": "Java"
}
然后,${name}被替换为Map对应的值"Bob”,${lang}被替换为Map对应的值"Java",最终输出的结果为:
Hello, Bob! You are learning Java!
标签:字符,匹配,String,正则表达式,可以,字符串 From: https://www.cnblogs.com/xiaoxiaowang/p/16822659.html