1、正则表达式
1.1、什么是正则表达式?
1.2、正则表达式的例子
正则表达式 | 匹配 |
---|---|
this is text | 匹配this is text |
this\s+is\s+text | 匹配这样的句子:this后接一个或多个空格,后面接上is,后面再接上一个或多个空格,再接上text |
^\d+(\.\d+)? | 定义一个必须以新的一行开始的模式。 \d匹配一个或多个数字。?号表示括号里面的内容是可选的。\.表示英文句号,()是用于分组。例如,它会匹配5、1.5和2.21 |
1.3、支持正则表达式的变成语言
正则表达式被大多数编程语言所支持,例如,java,perl,Grovy等都支持。遗憾的是,每种语言支持的正则表达式略有不同。
2、先决条件
以下的课程中,需要你已经有了java基础。
下面是一些通过JUnit验证的例子。如果您不想用JUnit的话,可以自己调整一下。要了解JUnit,请参考JUnit教程
3、正则表达式语法
3.1、常见的匹配符号
3.2、元字符
3.3、量词
3.4、分组和反向引用
你可以把你的正则表达式进行分组。可以在你的正则表达式中用()来分组,这允许你去指定一个可以重用的组。
此外,这些分组中也可以使用反向引用。反向引用可以储存匹配到的一个组,它可以用于后面的替换操作。
通过$可以指定一组。$1表示组1,$2表示组2,以此类推。
例如,假设你要替换一个字母后跟一个点或逗号之间的所有空格。
//去空格
// Removes whitespace between a word character and . or ,
String pattern = "(\\w)(\\s+)([\\.,])";
System.out.println("abc ,123 .".replaceAll(pattern, "$1$3"));
//提取标题之间的文本
// Extract the text between the two title elements
String pattern = "(?i)(<title.*?>)(.+?)()";
String updated = "<title='dd'>标题".replaceAll(pattern, "$2");
3.5、否定式向前匹配
否定式向前匹配提供了排除某种模式的可能性。它的定义为(?!pattern)。例如,a(?!b)匹配一个后面没有接一个b的字符a。既匹配ac中的a,但不匹配ab中的a。
3.6、在正则表达式中替代模式
你可以在正则表达式的开头添加模式修饰符。若要使用多种模式,可以这样写(?ismx)
(?i) 表示不区分大小写
(?s) 单行模式,使.匹配所有字符,包括换行符。
(?m) 多行模式,使得每一行都插入脱字符^和结束符$
3.7、java中的反斜杠\
反斜杠是java中的转义字符。这说明反斜杠在java中有预定义的作用。你必须使用两个反斜杠\\来表示一个反斜杠\。如果你要定义\w的话,你的正则表达式需要这样写\\w。如果你想让反斜杠表示一个文字,你需要输入\\\\。
4、在String的方法中使用正则表达式
4.1、解释String中处理正则表达式的方法
Java内置的String类支持正则表达式。String类有四个内置的方法支持正则表达式,分别是matches(),split(),replaceFirst()和replaceAll()。但replace()不支持正则表达式。
但是这些方法都没有优化性能。
package de.vogella.regex.test;
public class RegexTestStrings {
public static final String EXAMPLE_TEST = "This is my small example "
+ "string which I'm going to " + "use for pattern matching.";
public static void main(String[] args) {
System.out.println(EXAMPLE_TEST.matches("\\w.*"));
String[] splitString = (EXAMPLE_TEST.split("\\s+"));
System.out.println(splitString.length);// should be 14
for (String string : splitString) {
System.out.println(string);
}
// replace all whitespace with tabs
System.out.println(EXAMPLE_TEST.replaceAll("\\s+", "\t"));
}
}
4.2、例子
package de.vogella.regex.string;
public class StringMatcher {
// returns true if the string matches exactly "true"
public boolean isTrue(String s){
return s.matches("true");
}
// returns true if the string matches exactly "true" or "True"
public boolean isTrueVersion2(String s){
return s.matches("[tT]rue");
}
// returns true if the string matches exactly "true" or "True"
// or "yes" or "Yes"
public boolean isTrueOrYes(String s){
return s.matches("[tT]rue|[yY]es");
}
// returns true if the string contains exactly "true"
public boolean containsTrue(String s){
return s.matches(".*true.*");
}
// returns true if the string contains of three letters
public boolean isThreeLetters(String s){
return s.matches("[a-zA-Z]{3}");
// simpler from for
// return s.matches("[a-Z][a-Z][a-Z]");
}
// returns true if the string does not have a number at the beginning
public boolean isNoNumberAtBeginning(String s){
return s.matches("^[^\\d].*");
}
// returns true if the string contains a arbitrary number of characters except b
public boolean isIntersection(String s){
return s.matches("([\\w&&[^b]])*");
}
// returns true if the string contains a number less then 300
public boolean isLessThenThreeHundred(String s){
return s.matches("[^0-9]*[12]?[0-9]{1,2}[^0-9]*");
}
}
测试类:
package de.vogella.regex.string;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class StringMatcherTest {
private StringMatcher m;
@Before
public void setup(){
m = new StringMatcher();
}
@Test
public void testIsTrue() {
assertTrue(m.isTrue("true"));
assertFalse(m.isTrue("true2"));
assertFalse(m.isTrue("True"));
}
@Test
public void testIsTrueVersion2() {
assertTrue(m.isTrueVersion2("true"));
assertFalse(m.isTrueVersion2("true2"));
assertTrue(m.isTrueVersion2("True"));;
}
@Test
public void testIsTrueOrYes() {
assertTrue(m.isTrueOrYes("true"));
assertTrue(m.isTrueOrYes("yes"));
assertTrue(m.isTrueOrYes("Yes"));
assertFalse(m.isTrueOrYes("no"));
}
@Test
public void testContainsTrue() {
assertTrue(m.containsTrue("thetruewithin"));
}
@Test
public void testIsThreeLetters() {
assertTrue(m.isThreeLetters("abc"));
assertFalse(m.isThreeLetters("abcd"));
}
@Test
public void testisNoNumberAtBeginning() {
assertTrue(m.isNoNumberAtBeginning("abc"));
assertFalse(m.isNoNumberAtBeginning("1abcd"));
assertTrue(m.isNoNumberAtBeginning("a1bcd"));
assertTrue(m.isNoNumberAtBeginning("asdfdsf"));
}
@Test
public void testisIntersection() {
assertTrue(m.isIntersection("1"));
assertFalse(m.isIntersection("abcksdfkdskfsdfdsf"));
assertTrue(m.isIntersection("skdskfjsmcnxmvjwque484242"));
}
@Test
public void testLessThenThreeHundred() {
assertTrue(m.isLessThenThreeHundred("288"));
assertFalse(m.isLessThenThreeHundred("3288"));
assertFalse(m.isLessThenThreeHundred("328 8"));
assertTrue(m.isLessThenThreeHundred("1"));
assertTrue(m.isLessThenThreeHundred("99"));
assertFalse(m.isLessThenThreeHundred("300"));
}
}
5、Pattern和Matcher
package de.vogella.regex.test;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexTestPatternMatcher {
public static final String EXAMPLE_TEST = "This is my small example string which I'm going to use for pattern matching.";
public static void main(String[] args) {
Pattern pattern = Pattern.compile("\\w+");
// in case you would like to ignore case sensitivity,
// you could use this statement:
// Pattern pattern = Pattern.compile("\\s+", Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(EXAMPLE_TEST);
// check all occurance
while (matcher.find()) {
System.out.print("Start index: " + matcher.start());
System.out.print(" End index: " + matcher.end() + " ");
System.out.println(matcher.group());
}
// now create a new pattern and matcher to replace whitespace with tabs
Pattern replace = Pattern.compile("\\s+");
Matcher matcher2 = replace.matcher(EXAMPLE_TEST);
System.out.println(matcher2.replaceAll("\t"));
}
}
6、java正则表达式的例子
下面列出了正则表达式的典型例子
6.1、|
任务:写一个可以匹配包含Joe或Jim,或者同时包含两者的正则表达式。package de.vogella.regex.eitheror;
import org.junit.Test;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class EitherOrCheck {
@Test
public void testSimpleTrue() {
String s = "humbapumpa jim";
assertTrue(s.matches(".*(jim|joe).*"));
s = "humbapumpa jom";
assertFalse(s.matches(".*(jim|joe).*"));
s = "humbaPumpa joe";
assertTrue(s.matches(".*(jim|joe).*"));
s = "humbapumpa joe jim";
assertTrue(s.matches(".*(jim|joe).*"));
}
}
6.2、电话号码(欧美)
package de.vogella.regex.phonenumber;
import org.junit.Test;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class CheckPhone {
@Test
public void testSimpleTrue() {
String pattern = "\\d\\d\\d([,\\s])?\\d\\d\\d\\d";
String s= "1233323322";
assertFalse(s.matches(pattern));
s = "1233323";
assertTrue(s.matches(pattern));
s = "123 3323";
assertTrue(s.matches(pattern));
}
}
6.3、检查数量范围
package de.vogella.regex.numbermatch;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.junit.Test;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class CheckNumber {
@Test
public void testSimpleTrue() {
String s= "1233";
assertTrue(test(s));
s= "0";
assertFalse(test(s));
s = "29 Kasdkf 2300 Kdsdf";
assertTrue(test(s));
s = "99900234";
assertTrue(test(s));
}
public static boolean test (String s){
Pattern pattern = Pattern.compile("\\d{3}");
Matcher matcher = pattern.matcher(s);
if (matcher.find()){
return true;
}
return false;
}
}
6.4、链接检查
package de.vogella.regex.weblinks;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class LinkGetter {
private Pattern htmltag;
private Pattern link;
public LinkGetter() {
htmltag = Pattern.compile("<a\\b[^>]*href=\"[^>]*>(.*?)</a>");
link = Pattern.compile("href=\"[^>]*\">");
}
public List<String> getLinks(String url) {
List<String> links = new ArrayList<String>();
try {
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(new URL(url).openStream()));
String s;
StringBuilder builder = new StringBuilder();
while ((s = bufferedReader.readLine()) != null) {
builder.append(s);
}
Matcher tagmatch = htmltag.matcher(builder.toString());
while (tagmatch.find()) {
Matcher matcher = link.matcher(tagmatch.group());
matcher.find();
String link = matcher.group().replaceFirst("href=\"", "")
.replaceFirst("\">", "")
.replaceFirst("\"[\\s]?target=\"[a-zA-Z_0-9]*", "");
if (valid(link)) {
links.add(makeAbsolute(url, link));
}
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return links;
}
private boolean valid(String s) {
if (s.matches("javascript:.*|mailto:.*")) {
return false;
}
return true;
}
private String makeAbsolute(String url, String link) {
if (link.matches("http://.*")) {
return link;
}
if (link.matches("/.*") && url.matches(".*$[^/]")) {
return url + "/" + link;
}
if (link.matches("[^/].*") && url.matches(".*[^/]")) {
return url + "/" + link;
}
if (link.matches("/.*") && url.matches(".*[/]")) {
return url + link;
}
if (link.matches("/.*") && url.matches(".*[^/]")) {
return url + link;
}
throw new RuntimeException("Cannot make the link absolute. Url: " + url
+ " Link " + link);
}
}
6.5、检查重复的单词
\b(\w+)\s+\1\b
\b表示词边界,而\1表示第一组匹配到的内容。
6.6、匹配以新的一行开始的元素
(\n\s*)title
6.7、查找Non-Javadoc语句
(?s) /\* \(non-Javadoc\).*?\*/
6.7.1、Replacing the DocBook table statement with Asciidoc
<programlisting language="java">
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="./examples/statements/MyClass.java" />
</programlisting>
对应的正则表达式
`\s+<programlisting language="java">\R.\s+<xi:include xmlns:xi="http://www\.w3\.org/2001/XInclude" parse="text" href="\./examples/(.*).\s+/>\R.\s+</programlisting>`
目标可以是你的例子
`\R[source,java]\R----\R include::res/$1[]\R----