Java正则表达式基础知识及实例说明
众所周知,在程序开发中,难免会遇到需要匹配、查找、替换、判断字符串的情况发生,而这些情况有时又比较复杂,如果用纯编码方式解决,往往会浪费程序员的时间及精力。因此,学习及使用正则表达式,便成了解决这一矛盾的主要手段。
大 家都知道,正则表达式是一种可以用于模式匹配和替换的规范,一个正则表达式就是由普通的字符(例如字符a到z)以及特殊字符(元字符)组成的文字模式,它 用以描述在查找文字主体时待匹配的一个或多个字符串。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。
自从jdk1.4推出java.util.regex包,就为我们提供了很好的JAVA正则表达式应用平台。
因为正则表达式是一个很庞杂的体系,所以我仅例举些入门的概念,更多的请参阅相关书籍及自行摸索。
// 反斜杠
/t 间隔 ('/u0009')
/n 换行 ('/u000A')
/r 回车 ('/u000D')
/d 数字 等价于[0-9]
/D 非数字 等价于[^0-9]
/s 空白符号 [/t/n/x0B/f/r]
/S 非空白符号 [^/t/n/x0B/f/r]
/w 单独字符 [a-zA-Z_0-9]
/W 非单独字符 [^a-zA-Z_0-9]
/f 换页符
/e Escape
/b 一个单词的边界
/B 一个非单词的边界
/G 前一个匹配的结束
^为限制开头
^java 条件限制为以Java为开头字符
$为限制结尾
java$ 条件限制为以java为结尾字符
. 条件限制除/n以外任意一个单独字符
java.. 条件限制为java后除换行外任意两个字符
加入特定限制条件「[]」
[a-z] 条件限制在小写a to z范围中一个字符
[A-Z] 条件限制在大写A to Z范围中一个字符
[a-zA-Z] 条件限制在小写a to z或大写A to Z范围中一个字符
[0-9] 条件限制在小写0 to 9范围中一个字符
[0-9a-z] 条件限制在小写0 to 9或a to z范围中一个字符
[0-9[a-z]] 条件限制在小写0 to 9或a to z范围中一个字符(交集)
[]中加入^后加再次限制条件「[^]」
[^a-z] 条件限制在非小写a to z范围中一个字符
[^A-Z] 条件限制在非大写A to Z范围中一个字符
[^a-zA-Z] 条件限制在非小写a to z或大写A to Z范围中一个字符
[^0-9] 条件限制在非小写0 to 9范围中一个字符
[^0-9a-z] 条件限制在非小写0 to 9或a to z范围中一个字符
[^0-9[a-z]] 条件限制在非小写0 to 9或a to z范围中一个字符(交集)
在限制条件为特定字符出现0次以上时,可以使用「*」
J* 0个以上J
.* 0个以上任意字符
J.*D J与D之间0个以上任意字符
在限制条件为特定字符出现1次以上时,可以使用「+」
J+ 1个以上J
.+ 1个以上任意字符
J.+D J与D之间1个以上任意字符
在限制条件为特定字符出现有0或1次以上时,可以使用「?」
JA? J或者JA出现
限制为连续出现指定次数字符「{a}」
J{2} JJ
J{3} JJJ
文字a个以上,并且「{a,}」
J{3,} JJJ,JJJJ,JJJJJ,???(3次以上J并存)
文字个以上,b个以下「{a,b}」
J{3,5} JJJ或JJJJ或JJJJJ
两者取一「|」
J|A J或A
Java|Hello Java或Hello
「()」中规定一个组合类型
比如,我查询<a href=/"index.html/">index</a>中<a href></a>间的数据,可写作<a.*href=/".*/">(.+?)</a>
在使用Pattern.compile函数时,可以加入控制正则表达式的匹配行为的参数:
Pattern Pattern.compile(String regex, int flag)
大 家都知道,正则表达式是一种可以用于模式匹配和替换的规范,一个正则表达式就是由普通的字符(例如字符a到z)以及特殊字符(元字符)组成的文字模式,它 用以描述在查找文字主体时待匹配的一个或多个字符串。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。
自从jdk1.4推出java.util.regex包,就为我们提供了很好的JAVA正则表达式应用平台。
因为正则表达式是一个很庞杂的体系,所以我仅例举些入门的概念,更多的请参阅相关书籍及自行摸索。
// 反斜杠
/t 间隔 ('/u0009')
/n 换行 ('/u000A')
/r 回车 ('/u000D')
/d 数字 等价于[0-9]
/D 非数字 等价于[^0-9]
/s 空白符号 [/t/n/x0B/f/r]
/S 非空白符号 [^/t/n/x0B/f/r]
/w 单独字符 [a-zA-Z_0-9]
/W 非单独字符 [^a-zA-Z_0-9]
/f 换页符
/e Escape
/b 一个单词的边界
/B 一个非单词的边界
/G 前一个匹配的结束
^为限制开头
^java 条件限制为以Java为开头字符
$为限制结尾
java$ 条件限制为以java为结尾字符
. 条件限制除/n以外任意一个单独字符
java.. 条件限制为java后除换行外任意两个字符
加入特定限制条件「[]」
[a-z] 条件限制在小写a to z范围中一个字符
[A-Z] 条件限制在大写A to Z范围中一个字符
[a-zA-Z] 条件限制在小写a to z或大写A to Z范围中一个字符
[0-9] 条件限制在小写0 to 9范围中一个字符
[0-9a-z] 条件限制在小写0 to 9或a to z范围中一个字符
[0-9[a-z]] 条件限制在小写0 to 9或a to z范围中一个字符(交集)
[]中加入^后加再次限制条件「[^]」
[^a-z] 条件限制在非小写a to z范围中一个字符
[^A-Z] 条件限制在非大写A to Z范围中一个字符
[^a-zA-Z] 条件限制在非小写a to z或大写A to Z范围中一个字符
[^0-9] 条件限制在非小写0 to 9范围中一个字符
[^0-9a-z] 条件限制在非小写0 to 9或a to z范围中一个字符
[^0-9[a-z]] 条件限制在非小写0 to 9或a to z范围中一个字符(交集)
在限制条件为特定字符出现0次以上时,可以使用「*」
J* 0个以上J
.* 0个以上任意字符
J.*D J与D之间0个以上任意字符
在限制条件为特定字符出现1次以上时,可以使用「+」
J+ 1个以上J
.+ 1个以上任意字符
J.+D J与D之间1个以上任意字符
在限制条件为特定字符出现有0或1次以上时,可以使用「?」
JA? J或者JA出现
限制为连续出现指定次数字符「{a}」
J{2} JJ
J{3} JJJ
文字a个以上,并且「{a,}」
J{3,} JJJ,JJJJ,JJJJJ,???(3次以上J并存)
文字个以上,b个以下「{a,b}」
J{3,5} JJJ或JJJJ或JJJJJ
两者取一「|」
J|A J或A
Java|Hello Java或Hello
「()」中规定一个组合类型
比如,我查询<a href=/"index.html/">index</a>中<a href></a>间的数据,可写作<a.*href=/".*/">(.+?)</a>
在使用Pattern.compile函数时,可以加入控制正则表达式的匹配行为的参数:
Pattern Pattern.compile(String regex, int flag)
Java代码
- public class RegexHarnessTest
- {
- public static void main(String args[])
- {
- String[] regex = {"([\u4E00-\u9FA5]+,?)+",
- "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}",
- "\\d{4}[A-Z]{2}",
- "[0-9]{1.3}"};
- String[] input = {"开发高手,程序员的朋友,开发者的助手",
- "IP:71.42.164.8,192.168.1.1,7.78.3.221",
- "美国汽车牌照:3456MW,12345M,6789NY",
- "数字:345,678"};
- RegexHarness rh = new RegexHarness();
- for(int i=0;i<regex.length;i++)
- {
- rh.setRegex(regex[i]);
- rh.setInput(input[i]);
- if(rh.initialize())
- {
- System.out.println("\n-----匹配方式:全文匹配,方法:matches调用开始-----\n");
- rh.validateEntireText();
- System.out.println(rh.getResults());
- System.out.println("\n-----匹配方式:全文匹配,方法:matches调用结束-----\n");
- System.out.println("\n-----匹配方式:部分匹配,方法:find调用开始-----\n");
- rh.validatePartText();
- System.out.println(rh.getResults());
- System.out.println("\n-----匹配方式:部分匹配,方法:find调用结束-----\n");
- }
- else
- {
- System.out.println(rh.getRegexError());
- }
- }
- System.exit(0);
- }
- }
Java代码
- import java.util.regex.Matcher;
- import java.util.regex.Pattern;
- import java.util.regex.PatternSyntaxException;
- public class RegexHarness
- {
- /**regex表示正则表达式,input表示要匹配或验证的文本或字符串*/
- private String regex="",input="";
- /**regexError表示当正则表达式出现语法错误时,相关的错误信息
- * results表示匹配后的结果*/
- private String regexError="",results="";
- private Pattern pattern;
- private Matcher matcher;
- public RegexHarness()
- {
- this("","");
- }
- public RegexHarness(String regex,String input)
- {
- setRegex(regex);
- setInput(input);
- }
- /**
- * 初始化
- * @return
- */
- public boolean initialize()
- {
- try
- {
- /*
- * 使用Pattern类的静态compile方法,接收一个代表正则
- * 表达式的字符串(变量:regex)的参数,并返回一个指定的
- * 正则表达式的Pattern对象的pattern
- */
- pattern = Pattern.compile(regex);
- /*
- * 利用刚刚返回的Pattern类的实例pattern,并调用pattern
- * 的matcher方法。该方法接收一个用于匹配的实现了CharSequence
- * 接口的对象input,并将返回一个Matcher对象赋值给变量matcher。
- */
- matcher = pattern.matcher(input);
- return true;
- }
- catch (PatternSyntaxException pse) {
- regexError = "\n正则表达式语法错误!错误的相关信息如下:" +
- "\n当前的正则表达式是:" + pse.getPattern() +
- "\n错误描述:" + pse.getDescription() +
- "\n错误信息:" + pse.getMessage() +
- "\n错误索引:" + pse.getIndex();
- return false;
- }
- }
- /**
- * 根据正则表达式来匹配输入的整个文本,并得到匹配结果<br>
- * 本方法不返回任何数据,先调用matcher的方法matches,
- * matches方法根据给定的正则表达式来匹配的整个文本。
- * 如果整个文本都匹配给定的正则表达式,就调用matcher的
- * group方法,该方法返回与查找模式相匹配的查找对象的字符
- * 串,并将得到的匹配文本再赋值给字符串变量results,返回
- * 真值。
- */
- public void validateEntireText()
- {
- boolean findMathText = false;
- results = "当前的正则表达式是:" + regex +
- "\n当前匹配的文本是:" + input + "\n\n";
- if(matcher.matches())
- {
- results += "找到全文匹配的文本\"" + matcher.group() + "\"。\n";
- findMathText = true;
- }
- if(!findMathText)
- {
- results += "没有发现全文匹配的文本。\n";
- }
- }
- /**
- * 根据正则表达式来匹配输入的部分文本,并得到匹配结果<br>
- * 本方法不返回任何数据,但是调用的是matcher的方法find,
- * find方法根据给定的正则表达式来匹配的文本中的子字符串。
- * 和matches方法不同之处在于,只有被匹配的文本中的部分内容
- * 符合给定的正则表达式时,find方法才返回真值。
- */
- public void validatePartText()
- {
- boolean findMathText = false;
- results = "当前的正则表达式是:" + regex +
- "\n当前匹配的文本是:" + input + "\n\n";
- while(matcher.find())
- {
- results += "找到部分匹配的文本\"" + matcher.group()+
- "\"\t起始索引:" + matcher.start() +
- "\t结束索引:" + matcher.end() + "。\n";
- findMathText = true;
- }
- if(!findMathText)
- {
- results += "没有发现部分匹配的文本。\n";
- }
- }
- public String getResults()
- {
- return this.results;
- }
- public String getRegexError()
- {
- return this.regexError;
- }
- public void setRegex(String regex)
- {
- this.regex = regex;
- }
- public void setInput(String input)
- {
- this.input = input;
- }
- }
Java代码
- import javax.swing.JOptionPane;
- public class RegexStringReplace
- {
- public static void main(String args[])
- {
- String originalString = "This is 哈哈 JAVA code* * * * *";
- String output = "原始字符串:"+ originalString;
- //替换'*' 为 '^'
- originalString = originalString.replaceAll("\\*", "^ ");
- output+="\n*被替换成^ 后的字符串:"+originalString;
- //替换'哈哈'为'HaHa's'
- originalString = originalString.replaceAll("哈哈", "HaHa's");
- output+="\n\"哈哈\"替换成\"HaHa's\":"+originalString;
- //将字符串中的每个单词都替换成"word"
- output+="\n每个单词都替换成\"word\":"+originalString.replaceAll("\\w+", "word");
- JOptionPane.showMessageDialog(null, output,"Java正则表达式例子",JOptionPane.INFORMATION_MESSAGE);
- System.exit(0);
- }
- }
Java代码
- import javax.swing.JOptionPane;
- public class RegexStringReplaceFirstAndSplit
- {
- public static void main(String args[])
- {
- String originalString="1, one, 2, two, 3, three, 4, four, 5, five";
- String output = "原始字符串:\n" + originalString;
- //迭代3次,将字符串中第一次出现的数字替换成字符串'dight'
- for(int i=0;i<3;i++)
- {
- originalString = originalString.replaceFirst("\\d", "digit");
- }
- output += "\n头三个数字被替换成\"digit\"后的字符串:\n" + originalString;
- //分隔出现逗号的子字符串,逗号后面可以匹配任意的空白字符
- String[] result = originalString.split(",\\s*");
- output +="\n字符串依据逗号来分割后的结果";
- for(int i=0;i<result.length;i++)
- {
- output+="\n"+result[i];
- }
- JOptionPane.showMessageDialog(null, output,"java正则表达式",JOptionPane.INFORMATION_MESSAGE);
- System.exit(0);
- }
- }
Java代码
- import java.awt.Container;
- import java.awt.Font;
- import java.awt.GridLayout;
- import java.awt.event.ActionEvent;
- import java.awt.event.ActionListener;
- import javax.swing.JButton;
- import javax.swing.JFrame;
- import javax.swing.JLabel;
- import javax.swing.JOptionPane;
- import javax.swing.JPanel;
- import javax.swing.JTextField;
- public class RegexStringTest extends JFrame
- {
- private static final long serialVersionUID = -1564020173888781534L;
- private JTextField phoneTextField;
- private JTextField zipTextField;
- private JTextField addressTextField;
- private JTextField firstTextField;
- private JTextField lastTextField;
- private JTextField chineseTextField;
- private Font songTi = new Font("宋体",Font.PLAIN,12);
- public RegexStringTest()
- {
- super("基于字符串的正则表达式");
- //创建图形界面
- JLabel phoneLabel = new JLabel("电话");
- phoneLabel.setFont(songTi);
- JLabel zipLabel = new JLabel("邮政编码");
- zipLabel.setFont(songTi);
- JLabel addressLabel = new JLabel("通信地址");
- addressLabel.setFont(songTi);
- JLabel firstLabel = new JLabel("First Name:(英文,第一个字母必须大写)");
- firstLabel.setFont(songTi);
- JLabel lastLabel = new JLabel("Last Name:(英文,第一个字母必须大写)");
- lastLabel.setFont(songTi);
- JLabel chineseLabel = new JLabel("中文");
- chineseLabel.setFont(songTi);
- JButton okButton = new JButton("验证");
- okButton.setFont(songTi);
- okButton.addActionListener(new ActionListener()
- {
- //内部类开始
- public void actionPerformed(ActionEvent e) {
- validateDate();
- }//内部类结束
- });//调用addActionListener结束
- phoneTextField = new JTextField(15);
- zipTextField = new JTextField(6);
- addressTextField = new JTextField(35);
- firstTextField = new JTextField(20);
- lastTextField = new JTextField(20);
- chineseTextField = new JTextField(30);
- JPanel firstName = new JPanel();
- firstName.add(firstLabel);
- firstName.add(firstTextField);
- JPanel lastName = new JPanel();
- lastName.add(lastLabel);
- lastName.add(lastTextField);
- JPanel address = new JPanel();
- address.add(addressLabel);
- address.add(addressTextField);
- JPanel zipAndPhone = new JPanel();
- zipAndPhone.add(zipLabel);
- zipAndPhone.add(zipTextField);
- zipAndPhone.add(phoneLabel);
- zipAndPhone.add(phoneTextField);
- JPanel chinese = new JPanel();
- chinese.add(chineseLabel);
- chinese.add(chineseTextField);
- JPanel ok = new JPanel();
- ok.add(okButton);
- //把GUI部件添加在容器中
- Container container = getContentPane();
- container.setLayout(new GridLayout(6,1));
- container.add(firstName);
- container.add(lastName);
- container.add(address);
- container.add(zipAndPhone);
- container.add(chinese);
- container.add(ok);
- pack();
- setVisible(true);
- }//RegexStringTest构造器结束
- public static void main(String args[])
- {
- RegexStringTest application = new RegexStringTest();
- application.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- }
- /**
- * 处理鼠标点击事件
- */
- private void validateDate()
- {
- //确保每个文本框不为空
- if(lastTextField.getText().equals("") ||
- firstTextField.getText().equals("")||
- addressTextField.getText().equals("")||
- zipTextField.getText().equals("")||
- phoneTextField.getText().equals("")||
- chineseTextField.getText().equals(""))
- {
- JOptionPane.showMessageDialog(this, "每个栏目都必须填写");
- }
- else if(!firstTextField.getText().matches("[A-Z][a-zA-Z]*"))
- {//验证First Name是不是以大写字母的一个英文单词
- /*
- * [A-Z]匹配单个大写字母,其后面的[a-zA-Z]*表示可以匹配任意数目的
- * 字母。通常,在正则表达式中出现运算符(量词)"*"的时候,程序将匹配
- * "*"前的0个或多个子表达式。同理,"A*"和"A+"都与"A"匹配,但"A*"
- * 还可以匹配一个空的字符串。
- */
- JOptionPane.showMessageDialog(this, "First Name非法");
- }
- else if(!lastTextField.getText().matches("[A-Z][a-zA-Z]*"))
- {//验证Last Name是不是以大写字母开头的一个英文单词
- JOptionPane.showMessageDialog(this, "Last Name非法");
- }
- else if(!addressTextField.getText().matches("\\d+\\s+([a-zA-Z]+|[a-zA-Z]+\\s[a-zA-Z]+)"))
- {//验证地址是否为数字开始,并包含一个单词或者两个单词
- /*
- * 这里的地址格式是西方的格式,也就是门牌号在前,街名在后。
- * \\d+\\s+([a-zA-Z]+|[a-zA-Z]+\\s[a-zA-Z]+)
- * 首先是匹配任意的数字(\\d+),"\d"是表示数字字符,这里之所以要加上一个"\"
- * 是因为"\"在Java中是作用转义字符的。所以这里的"\\d"就正好表示正则表达
- * 式中的"\d"。然后,继续验证数字后面是否至少有一个空白字符(\\s+)。字符
- * "|"将表达式与其左边或者右边的字符串相匹配。如:Hello(Tom|Rich)就和
- * Hello Tom以及Hello Rich相匹配。括号用于将正则表达式的各个部分连接
- * 起来。这里字符"|"左边([a-zA-Z]+)匹配一个单词,而右边
- * ([a-zA-Z]+\\s[a-zA-Z]+)匹配两个单词,注意两个单词之间只能有一个空白
- * 字符(\\s)。因此,这里如果用户输入"123 Main"或者"123 Main Street"
- * 都是有效的。
- */
- JOptionPane.showMessageDialog(this, "地址非法");
- }
- else if(!zipTextField.getText().matches("\\d{5}"))
- {//验证邮政编码是否为一个5位数的数字
- /*
- * "\\d{5}"表明邮政编码匹配5个数字。另外可以用其他写法实现相同的功能
- * 如:"[0-9]{5}"
- */
- JOptionPane.showMessageDialog(this, "邮政编码非法");
- }
- else if(!phoneTextField.getText().matches("[1-9]\\d{2}-[1-9]\\d{2}-\\d{4}"))
- {//验证电话号码格式是否为123-456-7890并且区号和电话号码的第一位不能是数字0
- /*
- * [1-9]\\d{2}-[1-9]\\d{2}-\\d{4}
- * 本例采用的美国的电话号码形式,如123-456-7890,即头三位数字为区号
- * ,之后紧跟一个短横线,接着是电话号码的头三位,之后又是一个短横线,
- * 最后是电话号码的最后四位数。注意这里"[1-9]\\d{2}"表示匹配一个3位
- * 数的数字,但其第一个数字不能为0.如果希望123-4567890这种格式的电话
- * 号码也合法,可以修改"[1-9]\\d{2}-[1-9]\\d{2}-?\\d{4}"
- * 我们在第2个短横线后加一个"?"号,表示"-"可以出现,也可以不出现。
- */
- JOptionPane.showMessageDialog(this, "非法的电话号码");
- }
- else if(!chineseTextField.getText().matches("[\u4E00-\u9FA5]+"))
- {
- /*
- * [\u4E00-\u9FA5]+,验证了用户输入的数据是否全部为中文字符。
- */
- JOptionPane.showMessageDialog(this, "只能输入中文");
- }
- else
- {
- JOptionPane.showMessageDialog(this, "谢谢,您输入的完全合法");
- }
- }
- }