作为开发人员,正则是一定会接触到的内容,刚学习编程那时就开始用正则,提取爬虫爬取的页面内容。后面写Linux脚本,用正则过滤一些自己想要的内容。后续还是经常用到这块的知识点,还是需要整理下相关内容。
介绍
正则表达式(regex)
即一种搜索字符串中模式(pattern)
。模式可以是任意的字符串,或者是一个复杂的表达式。正则主要应用在字符串的搜索,编辑等操作上。
语法
1 如下egrep使用的是正则的语法,虽然是命令行,但内涵一样。.
代表任意的字符串,所以egrep搜索字符的时候所以的字符都是红色的,是被匹配的,而搜索Hello
的时候只有Hello
被匹配。
每一种编程语言都有正则表达式的实现,但是不同的语言之间支持的内容有轻微的差别。
常见正则规则
如下是一些常见的正则表达式类型。
正则表达式 | Description |
---|---|
. |
匹配任意字符 |
^regex |
仅仅匹配regex必须在一行的开头字符。 |
regex$ |
仅仅匹配regex出现在一行的末尾的字符串。比如 xxxxxregex。 而xxxregexyyy不行。 |
[abc] |
集合匹配,匹配a,b,c |
[abc][vz] |
集合匹配,可以匹配 av,az,bv,bz,cv,cz |
[^abc] |
加上取反符号,即不匹配abc的内容 |
[a-d1-7] |
匹配一个范围,具体位置可以是a-d中的任何一个字符,1-7之间的任何一个数字。 |
XlZ |
匹配X或Y |
正则元字符
一些预定义的元字符,让我们更容易使用正则表达式,可以看做替我们提前写好了上述的一些常见正则规则。
元字符 | 描述 |
---|---|
\d |
任何数字,即[0-9] |
\D |
任何非数字,即 [^0-9]
|
\s |
任何空白字符,即 [ \t\n\x0b\r\f]
|
\S |
任何非空白字符。即[^ \t\n\x0b\r\f]
|
\w |
任意单词类型字符, 即 [a-zA-Z_0-9]
|
\W |
任意非单词字符,即 [^\w]
|
\S+ |
多个非空白字符 |
\b |
匹配一个字边界,即字与空格间的位置。例如,"er\b"匹配"never"中的"er",但不匹配"verb"中的"er"。 |
\B |
非字边界匹配。"er\B"匹配"verb"中的"er",但不匹配"never"中的"er"。 |
正则量词
量词即匹配一个字符串出现了多少次。
字符 | 描述 |
---|---|
* | 零次或多次匹配前面的字符或子表达式。例如,zo* 匹配"z"和"zoo"。* 等效于 {0,}。 |
+ | 匹配一次或多次前面的字符,{1, } |
? | 匹配前一个字符不超过一次,即{0,1} |
{X} | X为数字,代表精确的匹配前一个字符几次。\d{3},代表精确匹配三个数字。 |
{X,Y} | 匹配前一个字符,X次到Y次之间 |
*? | 即只匹配一次就停止接下来的匹配。 |
Java使用
字符串中使用到正则的方法:
- matches
- split
- replaceFirst
- replaceAll
replace
方法不支持正则表达式。
部分元字符测试
后续补充
提取数字
@Test
public void regextExtractNumber(){
// 匹配任意的数字
Pattern p = Pattern.compile("\\d+");
Matcher m = p.matcher("string1234more567string890");
while(m.find()) {
System.out.println(m.group());
}
}
匹配手机号
@Test
public void regexPhone(){
// 手机号的第一位必须为 1。 ^[1]
// 手机号的第二位必须为 3,4,5,7,8 中的任意一个。 [34578]
// 紧接着有9位数字,只要是数字就行。[0-9]{9}
// 没有其它额外的内容。最后一位$
Pattern pattern = Pattern.compile("^[1][34578][0-9]{9}$");
String p1 = "13855683754";
String p2 = "15880975963";
System.out.println(pattern.matcher(p1).matches());
System.out.println(pattern.matcher(p2).matches());
}
匹配IP地址
这个属于比较复杂的案例,能看懂这个正则就ok了。
@Test
public void regexIpv4(){
// IP地址长度不固定。因此可能出现误匹配
// 将如下的正则表达式分为4段内容看即可。因为IP由三个 . 分隔开,以下正则也是又3个.分隔,最终以数字结尾。
// ^[01]?\\d\\d? 如果是三个数字,第一位必须是0或1。但是可以为1位到2位数字。
// 2[0-4]\\d 如果是以2开头的,那么接下来必须是0~4之间的一个数,第三位为任意数字
// 25[0-5] 如果是以25开头的,那么最后一个数字只能是 0~5。
// 其余一样
String ip_pattern =
"^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
"([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
"([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
"([01]?\\d\\d?|2[0-4]\\d|25[0-5])$";
Pattern pattern = Pattern.compile(ip_pattern);
List<String> strings = Arrays.asList(
"0.1.1.1",
"0.02.0.0",
"192.168.1.1",
"132.254.111.10",
"127.0.0.1"
);
for (String string : strings) {
System.out.println(pattern.matcher(string).matches());
}
}
提取html中href地址。
@Test
public void testHref(){
String aTag = "<a href=\"https://sensiolabs.com\" title=\"SensioLabs, PHP services and software solutions for enterprise and community.\">\n" +
" <img loading=\"eager\" height=\"17\" src=\"/images/pictos/slsponsor.svg\" alt=\"Symfony is sponsored by SensioLabs\">\n" +
" </a>";
// html的连接标签,属性为href。
// 地址中不为空,但可能有?#等内容,因此用非空匹配。
// href地址由""引起来,因此两边加上""
// 使用正则的反向引用特性
Pattern pattern = Pattern.compile("href=\"(\\S+)\".*");
Matcher matcher = pattern.matcher(aTag);
if (matcher.find()){
System.out.println(matcher.group(1));
}
}
最后
今天先到这里了