前端點滴(JS核心)(四)----傾盡所有
一、正則表達式(上)
1. 前言
正則表達式基礎:https://blog.csdn.net/Errrl/article/details/103880657
2. 匹配模式
參考blog:https://blog.csdn.net/weixin_42516949/article/details/80858913
// 貪婪: 儘可能多的匹配
// 非貪婪: 儘可能少的匹配
// 語法:將?緊跟在任何量詞 *、 +、? 或 {} 的後面,將會使量詞變爲非貪婪的(匹配儘量少的字符),和缺省使用的貪婪模式(匹配儘可能多的字符)正好相反。
//不加問號默認爲貪婪
var reg = /a.*c/
var string = 'aaaccaa'
var result = string.match(reg)
console.log(result) //=> ["aaacc"]
//加上問號爲非貪婪
var reg = /a.*?c/
var string = 'aaaccaa'
var result = string.match(reg)
console.log(result) //=> ["aaac"]
3. 正則表達式分組/捕獲和反向引用
捕獲和反向引用的語法的解釋:
正則中出現的小括號,就叫捕獲或者分組
在正則語法中(在/…/內),在捕獲的後面,用 “\1” 來引用前面的捕獲。用 “\2” 表示第二個捕獲的內容….
注意: 在正則語法外(如replace時),用 “$1” 來引用前面的捕獲。
<script>
var str = '1122 3434 5678 9090 1516';
// 要求:匹配連續四個數字
// var res = str.match(/\d{4}/g);
// var res = str.match(/[0-9]{4}/g);
// var res = str.match(/\d\d\d\d/g);
// 捕獲與引用
// 要求:匹配連續四個數字。要求1,3相同
// var res = str.match(/(\d)\d\1\d/g);
// 要求:匹配連續四個數字。要求1,3相同;2,4相同
// var res = str.match(/(\d)(\d)\1\2/g);
// 要求:匹配連續四個數字。要求1,2相同;3,4相同
var res = str.match(/(\d)\1(\d)\2/g);
console.log(res);
</script>
輸出結果:
禁止引用
(?:正則) 這個小括號中的內容不能夠被引用
4. 正則表達式匹配中文(utf-8編碼)
每個字符(中文、英文字母、數字、各種符號、拉丁文、韓文、日文等)都對應着一個Unicode編碼。
查看Unicode編碼,找到中文的部分,然後獲取中文的Unicode編碼的區間,就可以用正則匹配了。
前面我們用[a-z]表示小寫字母,[0-9]表示數字,這就是一個範圍表示,如果有一個數x能夠表示第一個中文,有一個數y能夠表示最後一箇中文,那麼[x-y]就可以表示所有的中文了。
中文的Unicode編碼從4E00開始,到9FA5結束。
[4E00-9FA5]這個區間就能夠表示中文。
JS語法:[\u4e00-\u9fa5]
完整的Unicode編碼表:http://blog.csdn.net/hherima/article/details/9045861
<script>
var str = '我是好人I’m a good man';
var result = str.match(/[\u4E00-\u9FA5]{4}/g);
console.log(result)
</script>
輸出結果:
5. 環視(斷言/零寬斷言/正向預測/負向預測)
(?=n)
匹配任何其後緊接指定字符串 n 的字符串。
有一個字符串是“abacad”,從裏面查找a,什麼樣的a呢?後面必須緊接b的a。
正則語法是: /a(?=b)/g
相反
(?!n)
匹配任何其後沒有緊接指定字符串 n 的字符串。
有一個字符串是“abacad”,從裏面查找a,什麼樣的a呢?後面不能緊接b的a。
正則語法是: /a(?!b)/g
<!-- 環視(斷言/零寬斷言/正向預測/負向預測) -->
<script>
var str = 'abacad';
// 查詢後面是 b 的 a
var res = str.match(/a(?=b)/g);
console.log(res); //=> ["a"]
</script>
<script>
var str = 'abacad';
// 查詢後面不是 b 的 a
var res = str.match(/a(?!b)/g);
console.log(res); //=> ["a", "a"]
</script>
<!-- 小例子 -->
<script>
var str = 'php7 and HTML5';
// 匹配後面跟着數字的字母字符串
var res = str.match(/[A-Za-z]+(?=\d)/g);
var res2 = str.match(/[A-Za-z]+(?!\d)/g);
console.log(res,res2) //=>["php", "HTML"], ["ph", "and", "HTM"]
</script>
輸出結果:
(1)環視的過濾效果
(?!B)[A-Z]
這種寫法,其實它是[A-Z]範圍裏,排除B的意思,前置的(?!B)
只是對後面數據的一個限定,從而達到過濾匹配的效果。
<!-- 環視的過濾效果 -->
<script>
var str = 'ABCDEFGHIJKLMN';
var res = str.match(/(?!B)[A-Z]/g);
console.log(res); //=> ["A", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N"]
</script>
輸出結果:
(2)環視的限定效果
在過濾的基礎上,限定正則表達式。用法相同。
輸出結果:
6. 正則對象的屬性和方法
正則對象中的成員方法和屬性的正確調用方式:
和String對象類似:
一種是直接量語法(/[a-z]/.exec())
另一種方法是實例化正則對象,然後通過對象去調用成員方法(var reg = new RegExp(/[a-z]/); reg.exec()
)
類似字符串:
- ‘hello’.substr(1);
- var s = new String(‘hello’); s.substr(1);
(1)exec方法和lastIndex屬性
exec方法執行一個正則匹配,只匹配一次,匹配到結果就返回一個數組類型的結果,匹配不到就返回null。並將表示匹配的位置 置爲下一個匹配的位置。
lastIndex一個整數,標示開始下一次匹配的字符位置。沒有更多匹配重置lastIndex爲0.
依次調用exec匹配下一個的例子:
依次調用exec,會將匹配的位置不斷的後移,直至結尾。
<script>
var str="The rain in Spain stays mainly in the plain";
var rex =/ain/g;
var i = rex.lastIndex;
var res = rex.exec(str);
console.log(i,res);
var i = rex.lastIndex;
var res = rex.exec(str);
console.log(i,res);
var i = rex.lastIndex;
var res = rex.exec(str);
console.log(i,res);
var i = rex.lastIndex;
var res = rex.exec(str);
console.log(i,res);
var i = rex.lastIndex;
var res = rex.exec(str);
console.log(i,res);
</script>
輸出結果:
(2)test 方法
test方法檢測目標字符串和正則表達式是否匹配,如果匹配返回true,不匹配返回false。
<!-- test方法 -->
<script>
/* 直接量語法調用 */
var str="The rain in Spain stays mainly in the plain";
var rex =/ain/g;
var res = rex.test(str);
console.log(res); //=> true
</script>
<script>
/* 實例化對象進行調用 */
var rex = new RegExp(/ain/,'g')
var str="The rain in Spain stays mainly in the plain";
var res = rex.test(str);
console.log(res); //=> true
</script>
輸出結果:
7. 支持正則表達式的 String 對象的方法
(1)search()
在字符串中搜索符合正則表達式的結果。如果找到結果返回結果的位置,停止向後檢索,也就是說忽略全局標識符g;如果沒有匹配結果,返回-1。
<script>
var str = 'Hello world';
var rex = /l/;
var res = str.search(rex);
console.log(res);
</script>
輸出結果:
(2)match()
在字符串中檢索匹配正則表達式的子串;如果匹配,返回包含匹配結果的一個數組;不匹配返回null。
不加全局g的情況:
獲取的結果只是第一個匹配的內容,匹配的內容中的第一個單元是匹配的結果,後面的單元是子表達式
非全局下:
<script>
var str = '1122 3434 5656 1234 1221 2002';
var rex = /\d(\d)\1\d/;
var res = str.match(rex);
console.log(res);
</script>
輸出結果:
全局下:
獲取的結果是所有匹配的內容,但是不包含子表達式。
<script>
/* 全局 */
var str = '1122 3434 5656 1234 1221 2002';
var rex = /\d(\d)\1\d/g;
var res = str.match(rex);
console.log(res);
</script>
輸出結果:
注意: 不管全局還是非全局調用多次和調用一次的結果相同
(3)split()
將字符串分割成數組:
特點是可以用正則表達式來分割字符串。
<!-- split -->
<script>
var str = '[email protected]';
// 用@來分割郵箱
var rex = /@/g;
var res = str.split(rex);
console.log(res); //=> ["1131260584", "qq.com"]
</script>
輸出結果:
(4)replace()
默認只替換一次,加g全部替換。加入全局的g:
<!-- replace -->
<script>
var str = 'hello world';
// var res = str.replace('l','L');//=>heLlo world
// var res = str.replace(/l/,'L');//=>heLlo world
var res = str.replace(/l/g,'L');//=>heLLo worLd
console.log(res);
</script>
替換的時候,使用"$1"表示第一個子表達式:
用$2表示第二個子表達式,以此類推。
/* 將abc替換成aabbcc */
<script>
var str = 'abc';
var res = str.replace(/([a-z])/g,'$1$1');
console.log(res);
</script>
輸出結果:
替換abc爲a[a-b-c]c ghk g[g-h-k]k
<script>
var str = 'abc';
var res = str.replace(/(b)/g,"[$` -$1- $']");
console.log(res);
</script>
輸出內容:
替換aaa bbb ccc爲Aaa Bbb Ccc,演示可以用函數來進行復雜的替換。
說明: replace具有遍歷的效果。
<script>
var str = 'aaa bbb ccc';
var res = str.replace(/[a-z]+/g,function(x){
return x.substr(0,1).toUpperCase()+x.substr(1);
});
console.log(res);
</script>
輸出結果:
8. 案例
(1)匹配手機號格式是否正確
/* 驗證手機格式 */
/**
*要求:
*1,1開頭
*2,廠商代號
*3,11位數全數字
*/
/* 正則表達式 */
/^1(56|59|50|57|36|89|58)\d{8}$/g
(2)匹配郵箱格式是否正確
/* 驗證郵箱格式 */
/**
*要求:
*1,@ 前6-14位數字與字母的組合,允許有符號比如 . - 等合法符號至多2個,@前一位不能是符號
*2,@ 後直接跟.com,也可以163.com,也可以163.com.cn
*/
/* 正則表達式 */
/^[A-z0-9][\w\.\-]{2}[A-z0-9]{3-11}@[a-z0-9]+(\.[A-z]+)+/g
(3)解決結巴程序
<script>
var str = '今今今今今今今今天晚晚晚晚晚晚晚上吃吃吃雞雞雞雞雞'
var r = /([\u4e00-\u9fa5])\1*/g; //表示先捕獲中文,再引用,利用量詞*匹配相同中文
var result = str.replace(r,'$1');
console.log(result);
</script>
結果:
(4)用戶名驗證
/* 用戶名的驗證 */
/* *
* 要求:
* 1,不能純字母
* 2,開頭不能是數字
* 3,長度範圍5-9
* 4,沒有符號
*/
/* 正則表達式 */
/(?!^[A-z]+$)^[A-z][A-z0-9]{4,8}$/g
9. PHP中的正則表達式
php中沒有修飾符。
(1)正則函數
1. preg_match()
相當於非全局匹配。
preg_match()返回匹配的次數,它的返回值是0或者是1。
- 0表示不匹配。
- 1表示匹配一次,因爲preg_match在匹配一次之後就停止向後檢索了。
<?php
$str = 'hello world';
$rex = '/[a-z]/';
/**
* preg_match
* 返回值是0或1
* $str 要執行正在匹配的字符串
* $rex 正則表達式
* $out 匹配內容,以一個數組的形式輸出
*/
echo preg_match($rex,$str,$out);
echo '<pre>'; //預輸出
print_r($out);
輸出結果:
帶子表達式的例子
/* 帶有子表達式匹配的例子 */
$str = '1122 3455 6677 8989';
$rex = '/(\d)\1(\d)\2/';
echo preg_match($rex,$str,$out);
echo '<pre>';
print_r($out);
輸出結果:
2. preg_match_all()
相當於全局匹配。
<?php
$str = 'hello world';
$rex = '/[a-z]/';
echo preg_match_all($rex,$str,$out);
echo '<pre>';
print_r($out);
輸出結果:
帶子表達式的例子
/* 帶有子表達式匹配的例子 */
$str = '1122 3455 6677 8989';
$rex = '/(\d)\1(\d)\2/';
echo preg_match_all($rex,$str,$out);
echo '<pre>';
print_r($out);
輸出結果:
3. preg_replace()
執行正則替換,替換字符串:
注意: 在php中preg_replace默認全部替換
<?php
$str = 'hello world';
$r = '/l/';
echo preg_replace($r,'L',$str);
輸出結果:
帶子表達式:
<?php
$str = 'abcd123';
$r = '/([a-z])/';
echo preg_replace($r,'$1$1',$str);
輸出結果:
替換數組:
<?php
$arr = array('javascript','php7','es6','html5');
$res = preg_replace('/(\d)/','$1$1',$arr);
echo '<pre>';
print_r($res);
輸出結果:
4. php中匹配中文
<?php
$res=array();
$str="你好aaaaa啊";
preg_match_all('/[\x{4e00}-\x{9fa5}]+/u',$str,$res);
echo '<pre>';
print_r($res);
//輸出
//Array ( [0] => Array ( [0] => 你好 [1] => 啊 ) )
輸出結果:
5. PHP中使用正則注意點
- PHP中的使用正則的使用除了//以外,外面還要加引號,這個引號要用單引號。
- 無論是JS中,還是PHP中,正則表達式的匹配模式默認都是貪婪模式。
6. 解決貪婪模式
貪婪模式:
上述代碼,查詢至少一個字母。但是在實際匹配的過程中,匹配到一個a之後,並沒有停止,而是繼續向後匹配,得到一個連續的字符串。這就是貪婪模式。
下面在正則表達式後面加入?,表示非貪婪模式:
默認是貪婪模式,必須使用非貪婪模式的例子:
PHP中,強制非貪婪模式:
加入大寫的修飾符U即可。