前言
在迁移md时,需要将 md 中的图片格式
与<img src=xxxx>
转换成附件中新的地址,这样就不得不使用正则来完成,借此机会对Java的正则做一个小的归纳
语法
正则的语法其实挺有意思,从语言的角度看,正则中没有动词、没有形容词,主要由名词与量词组成的一个字符串。名词首先有字符,然后由字符组成字符组,各个字符之间有着一定的逻辑关系,最后由量词来进行限定。
字符
这里的字符主要指的是单字符
字符 | 描述 |
. | 任意字符 |
\s | space空白符(空格、tab、换行、回车) |
\S | 非空白符 |
\d | 数字[0-9] |
\D | 非数字 |
\w | word词字符[a-zA-Z0-9] |
\W | 非词字符 |
^ | 一行的起始 |
$ | 一行的结束 |
\b | 词的边界 |
对于特殊字符需要用到转义符\
字符组[]
这里指的多个字符组成
字符 | 描述 |
[abc] | 包含a或b或c的任意字符,[] 取并集,表示或 |
[^abc] | 除了a、b、c之外的任意字符,[] 中的^ 否定 |
[a-zA-Z] | 从a-z或从A-Z的任意字符 |
[abc[hij]] | 包含a | b | c | h | i | j的任意字符 |
[a-z&&[hij]] | h | i | j 的任意字符,&& 取交集,表示与 |
逻辑关系
字符 | 描述 |
XY | Y跟着X后 |
X|Y | 或 |
[] | 或,见上 |
&& | 与,见上 |
^ | 非,在[]中表示非 |
() | 捕获组,限定这几个是一组,可以用来被引用 |
group()
我们在进行一个格式的匹配时,往往只需要提取出该格式中的某段字符,比如在这里的md图像格式是,![]()
,但我只选用()
中的图片地址进行替换。这样就用到了group。
分组用()
来指明是一组,然后可以通过Matcher.group(i)在指明是哪一组。
来看看分组的i:A(B(C))D
它分成了3组:组0是ABCD、组1是BC、组2是C.
应该是一个队列的方式见到(
就放到队列中。
量词
量词表示几个的意思,跟在字符后边
字符 | 描述 |
X? | 1个或零个X |
X+ | 1个或多个X |
X* | 任意个X |
X | 恰好n个X |
X{n,} | 至少n个X |
X{n,m} | 至少n个,且不超过m个X |
对于字符组时,X一般需要用()
限定起来
abc+,表示匹配ab,后边跟1个或多个c
(abc)+,表示1个或多个abc序列
其他
(?i)
使正则忽略大小写。
- 在匹配
.
或 {
或 [
或 (
或 ?
或 $
或 ^
或 *
这些特殊字符时,需要在前面加上 \\
,比如匹配 .
时,Java 中要写为 \\.
,但对于正则表达式来说就是 \.
。
- 在匹配
\
时,Java 中要写为 \\\\
,但对于正则表达式来说就是 \\
。
String中使用正则
字符串中使用正则有3个函数:
函数 | 描述 |
s.matches("regex") | 当正则表达式匹配整个字符串时,返回true |
s.split("regex") | 按匹配的正则表达式切片字符串 |
s.replaceAll("regex", "replacement") | 替换所有匹配的字符 |
s.replaceFirst("regex", "replacement") | 替换第一个匹配的字符 |
"-1234".matches("-?\\d+"); // true
"+9111".matches("(-|\\+)?\\d+"; // true
String posts = "Then, when you have found it, you must" +
"cut down the mighiest tree in the forest...";
posts.split(" "); // [Then, , when, you, have, found, it, ,you, must,...] 这样,逗号会被切在内
posts.split("\\W+"); // [Then, when, you, have, found, it, you, must ...] 这样,逗号等非字符的都会用做切分
posts.replaceFirst("f\\w+", "located"); // 将第一个found替换成located
Pattern、Matcher
这里将正则表达式抽象成了Pattern,将匹配抽象成了Matcher。
Pattern接口比较简单,主要就是compile进行构造。
Pattern p = Pattern.compile("\\w+");
Matcher的接口就比较丰富了,主要包括:
函数 | 说明 |
Matcher m = p.matcher("posts"); | 由Pattern构造Matcher |
m.find() | 迭代器,判断是否有匹配上的字符串 |
m.group() | 获取匹配上的字符串,group(1),可以获取分组 |
m.start() | 获取匹配上字符串所在的起始索引 |
m.end() | 获取匹配上字符串所在的结束索引 |
m.split("posts") | 用m去切分参数 |
m.replaceAll()/m.replaceFirst() | 替换 |
public static void main(String[] args) {
String text = "Hello Regex!";
Pattern pattern = Pattern.compile("\\w+");
// Java 中忽略大小写,有两种写法:
// Pattern pattern = Pattern.compile("\\w+", Pattern.CASE_INSENSITIVE);
// Pattern pattern = Pattern.compile("(?i)\\w+"); // 推荐写法
Matcher matcher = pattern.matcher(text);
// 遍例所有匹配的序列
while (matcher.find()) {
System.out.print("Start index: " + matcher.start());
System.out.print(" End index: " + matcher.end() + " ");
System.out.println(matcher.group());
}
// 创建第两个模式,将空格替换为 tab
Pattern replace = Pattern.compile("\\s+");
Matcher matcher2 = replace.matcher(text);
System.out.println(matcher2.replaceAll("\t"));
}
}
结果:
Start index: 0 End index: 5 Hello
Start index: 6 End index: 11 Regex
Hello Regex!
参考