前言
之前學過python的正則表達式,沒怎麼學懂,但是既然都是正則表達式學哪個語言應該沒有什麼區別纔是(
先寫個例子看看正則表達式是什麼!
用VS Code打開一個文件夾,新建一個module.html文件,把.vscode文件夾下的launch.json文件設置爲
{
"version": "0.2.0",
"configurations": [
{
"type": "chrome",
"request": "launch",
"name": "Launch Chrome against localhost",
"url": "file:///C:/Users/LX/Desktop/Code/JSLearning/module.html",
"webRoot": "${workspaceRoot}"
}
]
}
路徑按自己建的位置來。再新建一個regularExpression.js文件,寫入
var reg=/(\w+):\/\/([\w.]+)\/(\S*)/;
var text="Visit my blog at http://www.example.com/~david";
var result=text.match(reg);
if(result!=null){
var myUrl=result[0];
var myProtocol=result[1];
var myHost=result[2];
var myPath=result[3];
}
console.log("url = ",myUrl); // http:www.example.com/~david
console.log("protocol = ",myProtocol); //http <- (\w+)
console.log("host = ",myHost); //www.example.com <- ([\w.]+)
console.log("path = ",myPath); //~david <- (\S*)
console.log("local search result is ",result);//["http://www.example.com/~david", "http", "www.example.com", "~david"]
console.log("global search result is ",text.match(/(\w+):\/\/([\w.]+)\/(\S*)/g));// ["http://www.example.com/~david"]
console.log(RegExp(reg,"g"));
- 用sublime text的話很方便,畢竟這些代碼都是給遊覽器執行的,VSCode竟然這麼麻煩實在浪費時間。在sublime Text中的html文件內右擊在遊覽器內打開就行,VSCode中也有這個選項但是我一直弄不出效果233。
module.html寫入下面的代碼——這個文件在學習時就不用改太多了
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<!--
註釋
-->
<script type='text/javascript' src='regularExpression.js'></script>
<script type='text/javascript'>
</script>
</head>
<body>
</body>
</html>
運行結果在js文件註釋裏。有了這個例子,大家也就明白了,就算你還沒了解正則表達式的的偉大,你也知道了這個技術可以把url提取出來。對於想做爬蟲的我,知道這點就明白了,必須學懂這個。
- 下面的代碼都直接寫入regularExpression.js這個文件內運行,或者在遊覽器或VS Code的console端運行都可以—— clear() 命令可以清空console端
普通的字面量匹配
正則表達式在JS中是以斜杆爲邊界形式存在的。
console.log("JavaScript have much fun".match(/JavaScript/));
運行結果
這種程度的匹配是最簡單的,但是問題是太侷限了。必須把整個單詞拼得一字不差才行。你也許會想,對於這個匹配JavaScript的,這個字符串中這個單詞是第一個,後面還有空格,我只要找到空格就行了對吧!雖然可以實現,但是這樣的方式實在是太麻煩了!
爲了偷懶,於是正則表達式誕生了。(對別的技術也是這樣)
字符 | 匹配 |
---|---|
[…] | 滿足方框內條件的任意字符 |
[^…] | 不滿足方框內條件的任意字符 |
. (一個點) | 除換行符和其他Unicode行終止符的任意字符 |
\w | 任意ASCII字符,等價於 [a-zA-Z0-9] |
\W | 任意不是ASCII字符的字符,等價於[^a-zA-Z0-9] |
\s | 任何Unicode空白字符 |
\S | 任何非Unicode空白符的字符 |
\d | 任何ASCII數字,等價於[0-9] |
\D | 任何不是ASCII數字的字符,等價於[^0-9] |
[\b] | 退格(特例) |
{s,e} | 匹配前一項至少s次,最多m次 |
{s,} | 匹配前一項至少s次 |
{s} | 匹配前一項s次 |
? | 匹配前一項0次或1次,等價於{0,1} |
+ | 匹配前一項至少1次,等價於{1,} |
* | 匹配前一項至少0次 ,等價於{0,} |
現在來測試一下
下面這個例子中,匹配了數字 1 2 3。第一個只匹配了第一個數字1,第二個區別是在正則表達式後面加了修飾符g,表示全局的 —— 用 .global()方法可以返回這個正則表達式是否有g修飾符。
正則表達式修飾符 | 含義 |
---|---|
i | 執行不區分大小寫的匹配 |
g | 執行全局匹配 |
m | 執行多行匹配。 |
var pattern=/Java/gi;
var text="JavaScript is more fun than java!";
var result;
while(result=pattern.exec(text)){
console.log(
"Matched '"+result[0]+"'"
+" at position "+result.index +
"; next search begins at "+pattern.lastIndex
);
}
運行結果
Matched 'Java' at position 0; next search begins at 4
Matched 'java' at position 28; next search begins at 32
貪婪模式與非貪婪模式
匹配多次的匹配符都是貪婪的,有時處理字符串並不需要匹配所有滿足添加的字符,只需要匹配部分,這時候就需要在該項後面加上 ? —— 但是這個也不一定滿足條件,一般可以先試試。
可選、分組和引用
字符 | 含義 |
---|---|
豎槓 | 可選,匹配該符號的左邊子表達式或右表達式 |
(…) | 組合,將幾個字符合成一個單元,可以對這個單元進行 * + ?等操作。還能記住這個組合相匹配的字符串以供後面引用 |
(?:…) | 只進行組合 |
\n | 和組合一起用。用左括號做索引數n,用\n就可以代表該組合。 |
var a="'JavaScript\"er";
var b=/['"][^'"]*['"]/;
console.log(a.match(b));
運行結果
'JavaScript'
明明這個單詞左右的引號不同,但是還是被匹配出來了。如果我需要左右匹配相同的引號的話,需要使用\n
var a="'JavaScript'er";
var b=/(['"])[^'"]*\1/;
console.log(a.match(b));
運行結果
'JavaScript'
可以發現,如果組合起來就可以保存被匹配的字符,在之後用\n引用時,這個保存的字符就會有作用。這裏的作用就是使匹配的左右引號相同。
search()|replace()|match()|exec()|test()
search()參數是正則表達式。返回第一個與之匹配的字符串子串的起始位置,並且這個方法不支持g修飾符,會忽略g。
"JavaScript is not java".search(/java/gi); //0
replace()第一個參數是正則表達式,第二個是要替換的字符串。
"HHHHHhhhhhHHHHH".replace(/[H]+h/,"@"); //@hhhhHHHHH
match()參數是正則表達式。如果正則表達式是全局的,那麼其返回一個數組,元素是各個匹配到的子串,如果不是全局的,那麼也返回一個數組,第一個元素(比如a[0])是匹配到的子串,其他是匹配相應括號的子串(比如a[1]是滿足第一個括號匹配的子串)
這個例子前面有,這裏再寫一遍
var reg=/(\w+):\/\/([\w.]+)\/(\S*)/;
var text="Visit my blog at http://www.example.com/~david";
var result=text.match(reg);
if(result!=null){
var myUrl=result[0];
var myProtocol=result[1];
var myHost=result[2];
var myPath=result[3];
}
console.log("url = ",myUrl); // http:www.example.com/~david
console.log("protocol = ",myProtocol); //http <- (\w+)
console.log("host = ",myHost); //www.example.com <- ([\w.]+)
console.log("path = ",myPath); //~david <- (\S*)
console.log("local search result is ",result);//["http://www.example.com/~david", "http", "www.example.com", "~david"]
console.log("global search result is ",text.match(/(\w+):\/\/([\w.]+)\/(\S*)/g));// ["http://www.example.com/~david"]
exec()參數和match()一樣。每次執行match()時,返回的正則表達式對象的lastIndex不變,而exec()執行後每次lastIndex都是匹配的最後位置,如果exec匹配不到也會把lastIndex置零。
var pattern=/Java/gi;
var text="JavaScript is more fun than java!";
var result;
while(result=pattern.exec(text)){
console.log(
"Matched '"+result[0]+"'"
+" at position "+result.index +
"; next search begins at "+pattern.lastIndex
);
}
console.log(pattern.lastIndex); //0
test()參數是一個字符串。只返回真假。
var pattern=/java/i;
pattern.test("Javascript") ;//true
RegExp對象
前面講的有些函數就行RegExp對象的方法,這個對象的構造函數有兩個參數。第一個是正則表達式的字符串(在這個字符串中,原來正則表達式裏的反斜槓,在這裏就要寫成兩個反斜槓,畢竟是字符串傳遞進去的嘛),第二個參數是可選的修飾符,比如
var a=new RegExp("\\d{5}","g");//全局搜索,有連續5個數字的字符串