學習正則(告別複製貼上)

緣自世界發表於2018-01-09

知識學到自己手裡的才是自己的,如果複製,貼上別人的對自己幫助並不大,它只能幫自己解決一時的問題(有時還要花費自己大量的時間來查詢),而不能從根本上解決問題。

就好像前段時間我的的大學同學問了我一個正則問題,如何驗證使用者輸入的密碼必須包含字元、數字、特殊符號,他說在百度上找了大量的正則示例都不能解決問題,我就問然後呢,他給我說我問你,我當時就無語了,我當時因為正在做專案,一時沒想出來,我跟他說你沒試著換個思路,暫時沒有找到用一個正則解決這個問題的你就不會試著分別對字元,數字,特殊字元單獨判斷,然後進行與運算不就行了,再者說了從使用者體驗上用一個正則判斷後給出一個結果,使用者體驗也不好,應該針對使用者輸入不同的情況給出不同的提示資訊,如果密碼的組成沒有數字,就提示沒有數字,如果沒有字元就提示沒有字元…… , 如果以此類推覺得判斷過多,你可以再簡化處理,如只有密碼組成包含兩種,就提示缺少的一種,如果密碼組成只包含一種,就提示密碼應該有字元、數字、特殊符號組成。

這無形中給我上了生動的一課,正則不僅其他人忽視了,我也忽視了,有所欠缺。所以儘管最近在努力拿下設計模式這個高地,還是決定抽出一部分時間梳理一下自己的正則知識的掌握。

具有特殊含義的字元

下面只列出常用的字元,以及我個人對它們的分類。

分組和集合

  • () : 括號內的表示式表示一個分組
  • [] : 方括號內的表示式表示一個集合

運算子

  • ^ : 如果出現在集合([])中表示取反,否則是是定位符,從字串的前邊界開始匹配
  • | :它表示或的意思,就是起到或運算的作用
  • ?: : 它的作用是放在第一個選項前來消除相關匹配會被快取這種副作用

定位符

  • ^ : 上面已經說了它定義正則運算的前邊界
  • $ : 它定義了正則運算的後邊界
  • : 匹配一個字元的邊界(也即是字元和空白字元的分界)

字元類(代表一類字元)

  • d : 代表數字,而 D ,非數字
  • w : 代表單詞,而 W ,非單詞
  • s : 代表空白符,而 D ,非空白字元
  • . : 任意字元

限定符

它是用來指定匹配結果的長度或次數。

匹配該符號前面的表示式

  • + : 一次或更多次
  • * :零次或多次
  • : 零次或一次
  • {} : 匹配次數與話括號內的值有關。

    如果 {n} ,就是匹配n次;
    如果 {n,} ,就是匹配至少n次;
    如果 {n,m} ,就是匹配n到m之間的任意次數。

如何玩轉正則

正則用在字串的處理上,可以減少我們的js程式碼的書寫量,優化我們的程式碼,同時對於我們學習別人原始碼中複雜的正則已有幫助。

下面是一張來自知乎關於你是如何學會正規表示式的?問題的一張圖,掌握這張圖的正則,大概你就能解決你所面臨的大部分問題。

regular

/^s*[A-Za-z_$][w$]*(?:.[A-Za-z_$][w$]*|[`*?`]|[".*?"]|[d+]|[[A-Za-z_$][w$]*])*s*$/

下面推薦幾款視覺化的正則編輯器。

regexper (這是我最早接觸到的一款)

Regulex (這一款是我現在經常使用的)

RegExr (這一款功能很強大,對於學習正則很有幫助,如果學習正則的話強烈推薦)

js如何使用

正則是一個很強大的字串查詢和替換的方法。

以前我們有時侯總是在想將字串轉換為數字陣列,利用陣列的方法來處理字元,但是要知道字串就是我們在生活和工作中常見的形式,數字、陣列、Boolean型別的相對較少,尤其是最近在做微信開發時發現正則很重要,我同學的例子,只是給了我一個深入學習和研究的動力,這只是我的初步總結,以後有必要的話還會加強。

在JavaScript中我們使用 RegExp 來建立一個物件來實現正規表示式。

基本定義

一個正則有兩部分組成:正則主體和修飾符。

形式如下:

regExp = new RegExp(`pattern`, `flag`);

// 或者
regExp = /pattern/gmi

正則的修飾符一共有5種,分別為:

  • g : 所有匹配的情況,如果沒有它,只一種匹配情況
  • i : 忽略字元的大小寫
  • m : 支援多行
  • u : 支援 Unicode
  • y : 嚴格模式(返回指定位置後的匹配結果)

正則物件的一些方法

regexp.test(str)

test 方法返回值為true/false

let str = "Hello world!";
let regexp = /hello/i;
console.log(regexp.test(str));
regexp.exec(str)

由於這個方法不好用,所以很少有人使用。

let str = "Hello world!";
let regexp = /l(o)/ig; // 如果用exec返回所有的的匹配結果需要加上 ‘g’ 修飾符
let matchOne = regexp.exec(str);
console.log(matchOne[0]); // lo
console.log(matchOne[1]); // o
console.log(matchOne.index); // 3
console.log(matchOne.input); // Hello world!
console.log(matchOne.lastIndex); // 5

如果沒有匹配返回null

js中String可以使用正則的方法

在String的方法中使用正則,可以輕鬆的解決我們日常開發中的問題。

str.search()

如果有匹配結果,返回第一個匹配結果的首字元位置;否則,返回 `-1`。

let str = "Hello world!";
regexp = /o/i;
str.search(regexp); // 4

注;search 只能返回第一次匹配的結果,而不能返回其他匹配結果

str.match(str|reg)

let str = "Hello world!";
regexp = /o/i;
let result = str.match(regexp);

console.log(result[0]); // o
console.log(result.index); // 4
console.log(result.input); // Hello world!

我們發現 str.match() 的用法和 regexp.exec() 返回的結果很一樣,其實match的底層實現就是 regexp.exec(),使用也一樣,注意修飾符 g

str.split(reg|substr, limit)

將給定的字串按單詞為單位進行分割,返回一個由單片語成的陣列。

let str = `Hello world, my   name  is lzb.`
let regexp = /s+/i;
str.split(regexp); // ["Hello", "world,", "my", "name", "is", "lzb."]
str.split(regexp, 3) //  ["Hello", "world,", "my"]

在這個字串的方法中第二引數限制返回結果陣列的長度。

在返回的結果中,我們發現有的單詞帶有特殊符號,下面一個字串方法將實現清除特殊符號。

str.replace(str|reg, str|func)

如果要實現上面示例的清除字元中特殊符號的目標,我們可以使用 str.replace() ,效果如下:

let str = `Hello world, my   name  is lzb.`
let regexp = /[.,/#!$%^&*;:{}=-_`~()]/g;
str.replace(regexp, ``); // "Hello world my   name  is lzb"

或者

let str = `Hello world, my   name  is lzb.`
let regexp = /[^ws|-]/g;
str.replace(regexp, ``); // "Hello world my   name  is lzb"

然後,接著使用上面的 str.split() 方法即可,或者有同學可能想到如下方法:

let str = `Hello world, my   name  is u-lzb.`
let regexp = /[^w]+/g;
str.split(regexp); // ["Hello", "world", "my", "name", "is", "u", "lzb", ""]

這種方法不建議使用,問題很明顯,這裡就不多說了。

我們發現上面實現清除字串中特殊符號的方法有兩種,這兩種方法談不上孰優孰劣,它們各有優勢。如果在我們把字串中 work_up, call&apply::arga=b … 都當作特殊的單詞,我們就需要第一種方法;如果我們就是要中規中矩的單詞我們可以使用第二種方法。

如果第二個引數是func,介紹一個例子,字串中單詞的首字母大寫:

let str = `hello world`;
str.replace(/w+/g, (word) => word.substring(0,1).toUpperCase() + word.substring(1) );

字串還有 lengthindexOfconcattoLowerCasetoUpperCase 等方法,這裡就不一一介紹了。

推薦

如果喜歡碼題的同學可到https://www.hackerrank.com/domains/regex/re-introduction這個網站去。

github.com/lvzhenbang/article

相關文章