一、普通字符
普通字符包括以下类别:
1. a-z A-Z 0-9 !#@~等 非特殊含义字符
2. 反斜杠 \:第一个斜杠表示转义,第二个斜杠才是表示”\”字符,由于在java中表示”\”也需要转义,所以在java中是用正则表达式表示一个”\”需要写成”\\”
3. \t 制表符:由于”\t”在java中也表示制表符,所以可以直接使用”\t”,而使用”\t”的时候其中一个”\”代表转义,剩下来的”\t”在正则中正好表示制表符所以它们的效果一样
4. \n 换行符:同上
5. \f 换页符:同上
例子程序:
package com.sahooz.regex;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author sahooz
* @GITHUB: https://github.com/sahooz
* @CSDN: http://blog.csdn.net/u013028621
*/
public class NormalCharacter {
private static final String TARGET = "abcdefgHIJKLMN0123456789!#@~\\\t\n\f";
public static void main(String[] args) {
test1();
test2();
test3();
}
/**
* 测试第三类
*/
private static void test3() {
System.out.println("斜杠t的匹配结果:");
Pattern pattern = Pattern.compile("\t");
Matcher matcher = pattern.matcher(TARGET);
System.out.println(matcher.find());
System.out.println("双斜杠t的匹配结果:");
pattern = Pattern.compile("\\t");
matcher = pattern.matcher(TARGET);
System.out.println(matcher.find());
}
/**
* 测试第二类:"\"
*/
private static void test2() {
try {
System.out.println("双斜杠的匹配结果:");
Pattern pattern = Pattern.compile("\\"); //会报错,因为经过java转义表示正则里的"\",而正则里的"\"不能单独使用
Matcher matcher = pattern.matcher(TARGET);
if(matcher.find())
System.out.println(matcher.group());
} catch (Exception e) {
System.out.println("抛出异常!!");
}
System.out.println("四斜杠的匹配结果:");
Pattern pattern = Pattern.compile("\\\\");
Matcher matcher = pattern.matcher(TARGET);
if(matcher.find())
System.out.println(matcher.group());
}
/**
* 测试第一类
*/
private static void test1() {
char[] charArray = TARGET.toCharArray();
for (int i = 0; i < charArray.length; i++) {
char c = charArray[i];
if(c != '\\' && c != '\t' && c != '\n' && c != '\f') {
Pattern pattern = Pattern.compile(c + "");
Matcher matcher = pattern.matcher(TARGET);
if(matcher.find())
System.out.print(matcher.group());
}
}
System.out.println();
}
}
运行结果:
二、字符类
字符类相对于普通字符的区别是,它表示的是满足特定条件的一类字符中的一个,主要有以下类别:
1.[abc]: a、b 或 c(简单类)
2.[^abc]: 任何字符,除了 a、b 或 c(否定)
3.[a-zA-Z]: a 到 z 或 A 到 Z,两头的字母包括在内(范围)
4.[a-d[m-p]]: a 到 d 或 m 到 p:[a-dm-p](并集)
5.[a-z&&[def]]: d、e 或 f(交集)
6.[a-z&&[^bc]]: a 到 z,除了 b 和 c:[ad-z](减去)
7.[a-z&&[^m-p]]: a 到 z,而非 m 到 p:[a-lq-z](减去)
package com.sahooz.regex;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author sahooz
* github: https://github.com/sahooz
* CSDN: http://blog.csdn.net/u013028621
*/
public class CharacterClasses {
private static final String TARGET = "abcdefgHIJKLMN0123456789!#@~.";
public static void main(String[] args) {
System.out.print("所有属于IJK之中某一个的字符:");
print("[IJK]");
System.out.print("所有不属于IJK之中某一个的字符:");
print("[^IJK]");
System.out.print("所有属于b到g之中某一个的字符:");
print("[b-g]");
System.out.print("所有属于b到g或K到N之中某一个的字符:");
print("[b-g[K-N]]");
System.out.print("所有属于b到g或K到N之中某一个的字符:");
print("[b-gK-N]");
System.out.print("所有属于b到g且属于e到z之中某一个的字符:");
print("[b-g&&e-z]");
System.out.print("所有属于b到g且不属于e到z之中某一个的字符:");
print("[b-g&&[^e-z]]");
}
private static void print(String regex) {
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(TARGET);
while(matcher.find())
System.out.print(matcher.group());
System.out.println();
}
}
运行结果:
三、预定义字符类
特殊字符有:
1). 通配符,可以表示除换行符以外任意字符(换行符可能匹配,可能不匹配),匹配”.”本身需要使用”.”,
由于在java中”\”需要转义,所以写成”\.”,下同
2)\d 数字字符,[0-9]
3)\D 非数字字符,[^0-9]
4)\w 单词字符,[a-zA-Z_0-9]
5)\W 非单词字符,[^a-zA-Z_0-9]
6)\s 空白字符:[\t\n\x0B\f\r]
7)\S 非空白字符:[^\s]
例子程序:
package com.sahooz.regex;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author sahooz
* github: https://github.com/sahooz
* CSDN: http://blog.csdn.net/u013028621
*/
public class SpecialCharacter {
private static final String TARGET = "abcdefgHIJKLMN0123456789!#@~.^_\\s\\S\\w\\W\\d\\D\t\n";
public static void main(String[] args) {
System.out.println("目标字符串: " + TARGET);
System.out.print("与通配符.匹配的所有字符:");
print(".");
System.out.print("匹配.字符本身:");
print("\\.");
System.out.print("匹配所有数字字符:");
print("\\d");
System.out.print("匹配所有非数字字符:");
print("\\D");
System.out.print("匹配所有单词字符:");
print("\\w");
System.out.print("匹配所有非单词字符:");
print("\\W");
System.out.print("匹配所有的字符:");
print("[\\w\\W]");//同理可以使用"[\\s\\S]"
}
private static void print(String regex) {
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(TARGET);
while(matcher.find())
System.out.print(matcher.group());
System.out.println();
}
}
运行结果:
其中空白处其实包含了换行符制表符等。
四、匹配模式与边界匹配器
匹配模式:
1.单行模式(DOTALL): 整个文本视为一个字符串(一行),.能匹配所有字符的模式
2.多行模式(MULTILINE): 整个文本视为以换行符分隔的多行文本
3.大小写敏感模式: 大小写字母视为不一样的字符,比如a不能匹配到A
4.大小写不敏感模式(CASE_INSENSITIVE): 大小写字母视为一样的字符,比如a能匹配到A
默认模式为单行大小写敏感
边界匹配器:不代表任何字符,只表示目标字符(字符串)应该符合某个位置条件
1.^ 行的开头,单行模式下类似于\A
2.$ 行的结尾 ,单行模式下类似于\Z
3.\b 单词边界,也就是单词开始或结束的位置
4.\B 非单词边界,非\b位置
5.\A 输入的开头 ,无论单行多行模式
6.\Z 输入的结尾
例子程序:
package com.sahooz.regex;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author sahooz
* github: https://github.com/sahooz
* CSDN: http://blog.csdn.net/u013028621
*/
public class BoundaryMatchers {
private static final String TARGET = "Weak mind.\n" +
"Weak willpower.\n" +
"What is next?\n" +
"You cannot positively influence your life when you are not emotionally strong. Strength comes from within.\n" +
"Regardless of who your parents are and how much your husband earns, you cannot be a strong woman until you learn how to manage your emotions\n";
public static void main(String[] args) {
System.out.print("单行模式下^W(位于行开始位置的所有\"W\"字符)匹配的所有字符:");
print("^W", Pattern.DOTALL);
System.out.print("多行模式下^W(位于行开始位置的所有\"W\"字符)匹配的所有字符:");
print("^W", Pattern.MULTILINE);
System.out.print("多行模式下.$(位于行结束位置的所有字符)匹配的所有字符:");
print(".$", Pattern.MULTILINE);
System.out.print("多行模式下\\A.(整个输入的第一个能被\".\"匹配的字符)匹配的所有字符:");
print("\\AW", Pattern.MULTILINE);
System.out.print("单行模式下\\A.(整个输入的第一个能被\".\"匹配的字符)匹配的所有字符:");
print("\\AW", Pattern.DOTALL);
System.out.print(".\\Z(整个输入的结尾)匹配的所有字符:");
print(".\\Z", 0/*默认*/);
System.out.print(".\\b(位于单词边界的前一个字母)匹配的所有字符:");
print("[a-zA-Z]\\b", 0);
}
private static void print(String regex, int mode) {
Pattern pattern = Pattern.compile(regex, mode);
Matcher matcher = pattern.matcher(TARGET);
while(matcher.find())
System.out.print(matcher.group());
System.out.println();
}
}
运行结果:
五、量词与匹配模式
量词与匹配模式(贪婪模式、勉强模式)
贪婪模式: 趋向于最大长度匹配
勉强模式: 趋向于最小长度匹配
贪婪模式量词
X? X,一次或一次也没有
X* X,零次或多次
X+ X,一次或多次
X{n} X,恰好 n 次
X{n,} X,至少 n 次
X{n,m} X,至少 n 次,但是不超过 m 次
勉强模式量词
X?? X,一次或一次也没有
X*? X,零次或多次
X+? X,一次或多次
X{n}? X,恰好 n 次
X{n,}? X,至少 n 次
X{n,m}? X,至少 n 次,但是不超过 m 次
例子程序:
package com.sahooz.regex;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author sahooz
* github: https://github.com/sahooz
* CSDN: http://blog.csdn.net/u013028621
*/
public class Quantifiers {
private static final String TARGET = "abcdefgHIJKLMN0123456789!#@~.";
public static void main(String[] args) {
System.out.println("贪婪模式下[a-zA-Z]{3,5}的匹配结果(所有由3到5个字母组成的子序列):");
print("[a-zA-Z]{3,5}");
System.out.println("勉强模式下[a-zA-Z]{3,5}的匹配结果(所有由3到5个字母组成的子序列):");
print("[a-zA-Z]{3,5}?");
}
private static void print(String regex) {
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(TARGET);
while(matcher.find())
System.out.println(matcher.group());
}
}
运行结果:
可以看到,贪婪模式下每次匹配都是尽量选择满足条件的最长的子序列,在不够的情况下,才会匹配较短的序列;在勉强匹配下,匹配的是满足条件的最短的子序列。
六、捕获组
捕获组:用小括号括起来的一个匹配规则为一个捕获组,例如([a-z][0-9])+表示由一个或以上”a到z之间的字母与0到9之间的数字组合”组成的子序列。捕获组按照左边的小括号从1开始进行排序,每个捕获组最后一个匹配结果可以通过Matcher.group(int),没有匹配的时候返回的是null.0代表正则表达式整体的匹配结果,与Matcher.group()等效.
例子程序:
package com.sahooz.regex;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author sahooz
* github: https://github.com/sahooz
* CSDN: http://blog.csdn.net/u013028621
*/
public class CaptureGroup {
private static final String TARGET = "a0b1c2d3aabbccdde4f5";
public static void main(String[] args) {
//下面只有一个捕获组
Pattern p = Pattern.compile("([a-z][0-9])+[a-z]{2}");
Matcher m = p.matcher(TARGET);
while(m.find()){
for(int i = 0; i<= m.groupCount(); i++)
System.out.println(m.group(i));
}
System.out.println("=======分割线=======");
//看起好像一样,但是下面是两个捕获组
p = Pattern.compile("([a-z][0-9])+([a-z]){2}");
m = p.matcher(TARGET);
while(m.find()){
for(int i = 0; i<= m.groupCount(); i++)
System.out.println(m.group(i));
}
}
}
运行结果:
七、非捕获组
非捕获组,用于正则表达式匹配规则但不计入最终匹配结果
1.(?=X ) 零宽度正先行断言。仅当子表达式 X在此位置的右侧匹配时才继续匹配。例如,\w+(?=A)表示位于A前面的由一个以上单词字符组成的子序列,但不包括后面的这个A
2.(?!X) 零宽度负先行断言。仅当子表达式 X不在此位置的右侧匹配时才继续匹配。例如,例如,\w+(?!\A)表示不位于A前面的由一个以上单词字符组成的子序列,但不包括后面的这个A
3.(?<=X) 零宽度正后发断言。仅当子表达式 X在此位置的左侧匹配时才继续匹配。例如,(?<=A)99 与跟在 A后面的99的实例匹配
4.(?
package com.sahooz.regex;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author sahooz
* github: https://github.com/sahooz
* CSDN: http://blog.csdn.net/u013028621
*/
public class NonCapturing {
private static final String TARGET = "abcdAabcd$99A99";
public static void main(String[] args) {
System.out.println("位于A前面的由一个以上单词字符组成的子序列");
print("\\w+(?=A)");
System.out.println("不位于A前面的由两个以上字母组成的子序列");
print("[a-zA-Z]{2,}(?!=A)");
System.out.println("跟在 A后面的99");
print("(?<=A)99");
System.out.println("不跟在 A后面的99");
print("(?<!A)99");
}
private static void print(String regex) {
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(TARGET);
while(matcher.find())
System.out.print(matcher.group());
System.out.println();
}
}
运行结果:
八、反向引用
反向引用: 引用前一个捕获组的匹配结果,形式为\x,x代表捕获组的序号,比如([a-z])\1表示相同的两个小写字母组成的子序列,比如aa,bb,cc等
例子程序
package com.sahooz.regex;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author sahooz
* github: https://github.com/sahooz
* CSDN: http://blog.csdn.net/u013028621
*/
public class BackReferences {
private static final String TARGET = "aabbccdd";
public static void main(String[] args) {
print("([a-z])\\1");
}
private static void print(String regex) {
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(TARGET);
while(matcher.find())
System.out.println(matcher.group());
}
}
运行结果:
代码
github: https://github.com/sahooz/JavaRegexDemo
CSDN: http://download.csdn.net/download/u013028621/10143506