正則表達式: 定義一個搜索模式的字符串。正則表達式能夠用於搜索、編輯和操做文本.javascript
正則對文本的分析或修改過程爲: 首先正則表達式應用的是文本字符串(text/string
),它會以定義的模式從左到右匹配文本,每一個源字符只匹配一次.html
請說人話:java
正則就是用有限的符號,表達無限的序列!正則表達式
說白了人就是懶,想少寫多作!segmentfault
正則表達式 | 匹配 |
---|---|
this is text |
精確匹配字符串 "this is text" |
this\s+is\s+text |
匹配單詞 "this" 後跟一個或多個空格字符,後跟詞 "is" 後跟一個或多個空格字符,後跟詞 "text" |
^\d+(\.\d+)? |
^ 定義模式必須匹配字符串的開始,d+ 匹配一個或多個數字,? 代表小括號內的語句是可選的,\. 匹配 ".",小括號表示分組。例如匹配:"5"、"1.5" 和 "2.21" |
正則表達式 | 描述 |
---|---|
. |
匹配全部單個字符,除了換行符(Linux 中換行是 n,Windows 中換行是 rn) |
^regex |
正則必須匹配字符串開頭 |
regex$ |
正則必須匹配字符串結尾 |
[abc] |
複選集定義,匹配字母 a 或 b 或 c |
[abc][vz] |
複選集定義,匹配字母 a 或 b 或 c,後面跟着 v 或 z |
[^abc] |
當插入符 ^ 在中括號中以第一個字符開始顯示,則表示否認模式。此模式匹配全部字符,除了 a 或 b 或 c |
[a-d1-7] |
範圍匹配,匹配字母 a 到 d 和數字從 1 到 7 之間,但不匹配 d1 |
XZ |
匹配 X 後直接跟着 Z |
X|Z |
匹配 X 或 Z |
這些符號必需要記住bash
元字符是一個預約義的字符。ide
正則表達式 | 描述 |
---|---|
\d |
匹配一個數字,是 [0-9] 的簡寫 |
\D |
匹配一個非數字,是 [^0-9] 的簡寫 |
\s |
匹配一個空格,是 [ \t\n\x0b\r\f] 的簡寫 |
\S |
匹配一個非空格 |
\w |
匹配一個單字字符(大小寫字母、數字、下劃線),是 [a-zA-Z_0-9] 的簡寫 |
\W |
匹配一個非單字字符(除了大小寫字母、數字、下劃線以外的字符),等同於 [^\w] |
限定符定義了一個元素能夠發生的頻率。工具
正則表達式 | 描述 | 舉例 |
* |
匹配 >=0 個,是 {0,} 的簡寫 |
X* 表示匹配零個或多個字母 X,.* 表示匹配任何字符串 |
+ |
匹配 >=1 個,是 {1,} 的簡寫 |
X+ 表示匹配一個或多個字母 X |
? |
匹配 1 個或 0 個,是 {0,1} 的簡寫 |
X? 表示匹配 0 個或 1 個字母 X |
{X} |
只匹配 X 個字符 | \d{3} 表示匹配 3 個數字,.{10} 表示匹配任何長度是 10 的字符串 |
{X,Y} |
匹配 >=X 且 <=Y 個 | \d{1,4} 表示匹配至少 1 個最多 4 個數字 |
*? |
若是 ? 是限定符 * 或 + 或 ? 或 {} 後面的第一個字符,那麼表示非貪婪模式(儘量少的匹配字符),而不是默認的貪婪模式 |
小括號 ()
能夠達到對正則表達式進行分組的效果。測試
模式分組後會在正則表達式中建立反向引用。反向引用會保存匹配模式分組的字符串片段,這使得咱們能夠獲取並使用這個字符串片段。ui
在以正則表達式替換字符串的語法中,是經過 $
來引用分組的反向引用,$0
是匹配完整模式的字符串(注意在 JavaScript 中是用 $&
表示);$1
是第一個分組的反向引用;$2
是第二個分組的反向引用,以此類推。
package com.wuxianjiezh.demo.regex;
public class RegexTest {
public static void main(String[] args) {
// 去除單詞與 , 和 . 之間的空格
String Str = "Hello , World .";
String pattern = "(\\w)(\\s+)([.,])";
// $0 匹配 `(\w)(\s+)([.,])` 結果爲 `o空格,` 和 `d空格.`
// $1 匹配 `(\w)` 結果爲 `o` 和 `d`
// $2 匹配 `(\s+)` 結果爲 `空格` 和 `空格`
// $3 匹配 `([.,])` 結果爲 `,` 和 `.`
System.out.println(Str.replaceAll(pattern, "$1$3")); // Hello, World.
}
}
複製代碼
上面的例子中,咱們使用了 [.]
來匹配普通字符 .
而不須要使用 [\\.]
。由於正則對於 []
中的 .
,會自動處理爲 [\.]
,即普通字符 .
進行匹配。
當咱們在小括號 ()
內的模式開頭加入 ?:
,那麼表示這個模式僅分組,但不建立反向引用。
package com.wuxianjiezh.regex;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexTest {
public static void main(String[] args) {
String str = "img.jpg";
// 分組且建立反向引用
Pattern pattern = Pattern.compile("(jpg|png)");
Matcher matcher = pattern.matcher(str);
while (matcher.find()) {
System.out.println(matcher.group());//$0
System.out.println(matcher.group(1));//$1
}
}
}
複製代碼
運行結果爲:
jpg
jpg
若源碼改成:
package com.wuxianjiezh.regex;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexTest {
public static void main(String[] args) {
String str = "img.jpg";
// 分組但不建立反向引用
Pattern pattern = Pattern.compile("(?:jpg|png)");
Matcher matcher = pattern.matcher(str);
while (matcher.find()) {
System.out.println(matcher.group());
System.out.println(matcher.group(1));
}
}
}
複製代碼
運行結果爲:
jpg Exception in thread "main" java.lang.IndexOutOfBoundsException: No group 1 at java.util.regex.Matcher.group(Matcher.java:538) at com.wuxianjiezh.regex.RegexTest.main(RegexTest.java:15)
Java 中能夠在小括號中使用 ? 將小括號中匹配的內容保存爲一個名字爲 name 的副本。
package com.wuxianjiezh.regex;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexTest {
public static void main(String[] args) {
String str = "@wxj 你好啊";
Pattern pattern = Pattern.compile("@(?<first>\\w+\\s)"); // 保存一個副本
Matcher matcher = pattern.matcher(str);
while (matcher.find()) {
System.out.println(matcher.group());
System.out.println(matcher.group(1));
System.out.println(matcher.group("first"));
}
}
}
複製代碼
運行結果爲:
@wxj wxj wxj
咱們能夠建立否認先行斷言模式的匹配,即某個字符串後面不包含另外一個字符串的匹配模式。
否認先行斷言模式經過 (?!pattern)
定義。好比,咱們匹配後面不是跟着 "b" 的 "a":
a(?!b)
複製代碼
能夠在正則的開頭指定模式修飾符。
(?i)
使正則忽略大小寫。(?s)
表示單行模式("single line mode")使正則的 .
匹配全部字符,包括換行符。(?m)
表示多行模式("multi-line mode"),使正則的 ^
和 $
匹配字符串中每行的開始和結束。反斜槓 \
在 Java 中表示轉義字符,這意味着 \
在 Java 擁有預約義的含義。
這裏例舉兩個特別重要的用法:
.
或 {
或 [
或 (
或 ?
或 $
或 ^
或 *
這些特殊字符時,須要在前面加上 \\
,好比匹配 .
時,Java 中要寫爲 \\.
,但對於正則表達式來講就是 \.
。\
時,Java 中要寫爲 \\\\
,但對於正則表達式來講就是 \\
。注意:Java 中的正則表達式字符串有兩層含義,首先 Java 字符串轉義出符合正則表達式語法的字符串,而後再由轉義後的正則表達式進行模式匹配。
[jpg|png]
表明匹配 j
或 p
或 g
或 p
或 n
或 g
中的任意一個字符。(jpg|png)
表明匹配 jpg
或 png
。在 Java 中有四個內置的運行正則表達式的方法,分別是 matches()
、split())
、replaceFirst()
、replaceAll()
。注意 replace()
方法不支持正則表達式。
方法 | 描述 |
---|---|
s.matches("regex") |
當僅且當正則匹配整個字符串時返回 true |
s.split("regex") |
按匹配的正則表達式切片字符串 |
s.replaceFirst("regex", "replacement") |
替換首次匹配的字符串片斷 |
s.replaceAll("regex", "replacement") |
替換全部匹配的字符 |
package com.wuxianjiezh.regex;
public class RegexTest {
public static void main(String[] args) {
System.out.println("wxj".matches("wxj"));
System.out.println("----------");
String[] array = "w x j".split("\\s");
for (String item : array) {
System.out.println(item);
}
System.out.println("----------");
System.out.println("w x j".replaceFirst("\\s", "-"));
System.out.println("----------");
System.out.println("w x j".replaceAll("\\s", "-"));
}
}
複製代碼
運行結果
true
----------
w
x
j
----------
w-x j
----------
w-x-j
複製代碼
Java 中使用正則表達式須要用到兩個類,分別爲 java.util.regex.Pattern
和 java.util.regex.Matcher
。
第一步,經過正則表達式建立模式對象 Pattern
。
第二步,經過模式對象 Pattern
,根據指定字符串建立匹配對象 Matcher
。
第三步,經過匹配對象 Matcher
,根據正則表達式操做字符串。
很是好的示例
package com.wuxianjiezh.regex;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexTest {
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!
複製代碼
[\u4e00-\u9fa5]+
表明匹配中文字。
package com.wuxianjiezh.regex;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexTest {
public static void main(String[] args) {
String str = "閑人到人間";
Pattern pattern = Pattern.compile("[\\u4e00-\\u9fa5]+");
Matcher matcher = pattern.matcher(str);
while (matcher.find()) {
System.out.println(matcher.group());
}
}
}
複製代碼
運行結果:
閑人到人間
複製代碼
好比,匹配 1990 到 2017。
**注意:**這裏有個新手易範的錯誤,就是正則 [1990-2017]
,實際這個正則只匹配 0
或 1
或 2
或 7
或 9
中的任一個字符。
正則表達式匹配數字範圍時,首先要肯定最大值與最小值,最後寫中間值。
正確的匹配方式:
package com.wuxianjiezh.regex;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexTest {
public static void main(String[] args) {
String str = "1990\n2010\n2017";
// 這裏應用了 (?m) 的多行匹配模式,只爲方便咱們測試輸出
// "^1990$|^199[1-9]$|^20[0-1][0-6]$|^2017$" 爲判斷 1990-2017 正確的正則表達式
Pattern pattern = Pattern.compile("(?m)^1990$|^199[1-9]$|^20[0-1][0-6]$|^2017$");
Matcher matcher = pattern.matcher(str);
while (matcher.find()) {
System.out.println(matcher.group());
}
}
}
複製代碼
運行結果:
1990
2010
2017
複製代碼
好比,獲取圖片文件內容,這裏咱們考慮了一些不規範的 img 標籤寫法:
package com.wuxianjiezh.regex;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexTest {
public static void main(String[] args) {
String str = "<img src='aaa.jpg' /><img src=bbb.png/><img src=\"ccc.png\"/>" +
"<img src='ddd.exe'/><img src='eee.jpn'/>";
// 這裏咱們考慮了一些不規範的 img 標籤寫法,好比:空格、引號
Pattern pattern = Pattern.compile("<img\\s+src=(?:['\"])?(?<src>\\w+.(jpg|png))(?:['\"])?\\s*/>");
Matcher matcher = pattern.matcher(str);
while (matcher.find()) {
System.out.println(matcher.group("src"));
}
}
}
複製代碼
運行結果:
aaa.jpg
bbb.png
ccc.png
複製代碼
好比,獲取 div 標籤中的文本內容:
package com.wuxianjiezh.regex;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexTest {
public static void main(String[] args) {
String str = "<div>文章標題</div><div>發佈時間</div>";
// 貪婪模式
Pattern pattern = Pattern.compile("<div>(?<title>.+)</div>");
Matcher matcher = pattern.matcher(str);
while (matcher.find()) {
System.out.println(matcher.group("title"));
}
System.out.println("--------------");
// 非貪婪模式
pattern = Pattern.compile("<div>(?<title>.+?)</div>");
matcher = pattern.matcher(str);
while (matcher.find()) {
System.out.println(matcher.group("title"));
}
}
}
複製代碼
運行結果:
文章標題</div><div>發佈時間
--------------
文章標題
發佈時間
複製代碼
正則表達式30分鐘入門教程 https://deerchao.net/tutorials/regex/regex.htm
Java的正則表達式工具 http://www.regexplanet.com/advanced/java/index.html
正則表達式語法篇 https://yanhaijing.com/javascript/2017/08/06/regexp-syntax/
正則表達式語法詳解篇 https://blog.csdn.net/yaerfeng/article/details/28855587#reg
JavaScript正則表達式 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions
問題1:關於空格
針對tab鍵帶來的多個空格問題,有時候咱們針對帶空格的一行數據要進行切割,若是有多個空格就會出現就會切割空格出現,咱們想把空格都去掉,因此須要用到某些方法。
解決方案: 利用正則表達式來匹配空格\\s+
首先利用split(「\s+」);方法來對字符串切割,儘量的匹配空格,這裏也挺有意思,由於空格數目不同,能夠動態變換匹配的空格數量,這個實現原理能夠看看底層原理,挺有意思。
String string="a b a a ";
for(String a:string.split("\\s+")){
System.out.println(a);
}
複製代碼
問題2:[] {} () 的使用區別
()
是爲了提取匹配的字符串。表達式中有幾個()
就有幾個相應的匹配字符串。(\s*)
表示連續空格的字符串。[]
是定義匹配的字符範圍。好比 [a-zA-Z0-9]
表示相應位置的字符要匹配英文字符和數字。[\s*]
表示空格或者*號。{}
通常用來表示匹配的長度,好比 \s{3}
表示匹配三個空格,\s{1,3}
表示匹配一到三個空格。(0-9)
匹配 '0-9′ 自己。[0-9]*
匹配數字(注意後面有 *
,能夠爲空)[0-9]+
匹配數字(注意後面有 +,不能夠爲空){1-9}
寫法錯誤。[0-9]{0,9}
表示長度爲 0 到 9 的數字字符串問題3: ()和[]有本質的區別
()
內的內容表示的是一個子表達式,()自己不匹配任何東西,也不限制匹配任何東西,只是把括號內的內容做爲同一個表達式來處理!
例如:(ab){1,3},就表示ab一塊兒連續出現最少1次,最多3次。若是沒有括號的話,ab{1,3},就表示a,後面緊跟的b出現最少1次,最多3次。另外,括號在匹配模式中也很重要。查看前面的介紹 []表示匹配的字符在[]中,而且只能出現一次,而且特殊字符寫在[]會被當成普通字符來匹配。例如[(a)],會匹配(、a、)、這三個字符。 因此() [] 不管是做用仍是表示的含義,都有天壤之別,沒什麼聯繫