講給前端的正則表達式(3):使用 ES6 特性[每日前端夜話0x104]

  • 2019 年 12 月 24 日
  • 筆記

每日前端夜話0x104

每日前端夜話,陪你聊前端。

每天晚上18:00準時推送。

正文共:1638 字

預計閱讀時間:7分鐘

翻譯:瘋狂的技術宅

作者:wanago

來源:wanago.io

前文:

  • 講給前端的正則表達式(1):基本概念
  • 講給前端的正則表達式(2):寫出更優雅、更精確的正則表達式

到現在為止,我們已經介紹了許多正則表達式的功能。但是還有更多。這次我們將會學習一些更高級的概念,例如搜索和覆蓋 JavaScript 中 RegExp 對象的更多功能。我們還將學習如何使用 ES6 帶來的一些功能。開始吧!

exec

這是一種執行搜索字符串中的匹配項的方法(類似於 test 方法),但是它返回的結果是數組(或 null)。其結果還有其他一些屬性,例如 indexinput

const string = 'fileName.png, fileName2.png, fileName3.png';  const regexp = /fileName[0-9]?.png/g;    regexp.exec(string);    [    0: "fileName.png",    index: 0,    input: "fileName.png, fileName2.png, fileName3.png"  ]  

index 是匹配項的位置,input 是提供的字符串。請注意,我在這裡用的是 global 標誌,在課程的第一部分中已提到過。所以我們可以通過多次調用 exec 在字符串中尋找多個匹配項。它將 RegExp 對象的 lastIndex 屬性設置為一個數字,該數字指示搜索停止的位置。

let resultArray;  while((resultArray = regexp.exec(string)) !== null) {    console.log(resultArray[0], regexp.lastIndex);  }    // fileName.png  12  // fileName2.png 27  // fileName3.png 42  

正則表達式中的分組

使用正則表達式,不僅可以檢查字符串是否匹配,還可以在忽略不必要字符的同時提取某些信息。可以使用帶有圓括號的分組。

function getDateFromString(dateString) {    const regexp = /([0-9]{2})-([0-9]{2})-([0-9]{4})/;    const result = regexp.exec(dateString);    if(result) {      return {        day: result[1],        month: result[2],        year: result[3]      }    }  }    getDateFromString('14-05-2018');  
{    day: '14',    month: '05',    year: '2018'  }  

在這種情況下,我們提取了三組字符,而忽略了破折號。只需注意 result [0] 將是匹配的完整字符串。

已經有一個處於第4階段的命名組提案【https://github.com/tc39/proposal-regexp-named-groups】,並且在上述用例中被證明是有幫助的。Axel Rauschmayer 在 2ality 博客上的文章【http://2ality.com/2017/05/regexp-named-capture-groups.html】中對此進行了很好的描述。

嵌套分組

你可以嵌套分組:

function getYearFromString(dateString) {    const regexp = /[0-9]{2}-[0-9]{2}-([0-9]{2}([0-9]{2}))/;    const result = regexp.exec(dateString);    if(result) {      return {        year: result[1],        yearShort: result[2]      }    }  }    getYearFromString('14-05-2018');  
{    year: '2018',    yearShort: '18'  }  

在模式的 ([0-9]{2}([0-9]{2})) 部分中,我們將一組嵌套在另一組中。多虧了這一點,我們得到了表示年份的短字符串。

條件模式

還有另一個有用的功能,即 OR 語句。我們可以用 | 字符實現:

function doYearsMatch(firstDateString, secondDateString) {    const execResult = /[0-9]{2}-[0-9]{2}-([0-9]{4})/.exec(firstDateString);    if(execResult) {      const year = execResult[1];      const yearShort = year.substr(2,4);      return RegExp(`[0-9]{2}-[0-9]{2}-(${year}|${yearShort})`).test(secondDateString);    }  }    doYearsMatch('14-05-2018', '12-02-2018'); // true  doYearsMatch('14-05-2018', '24-04-18');   // true  

按照我們的模式,(${year}|${yearShort}) 將會匹配年份,即使第二個年份以簡短形式提供。

全部捕獲

與組一起工作時,還有一個特別有用的地方:(. *)

function getResolution(resolutionString) {    const execResult = /(.*) ?x ?(.*)/.exec(resolutionString);    if(execResult) {      return {        width: execResult[1],        height: execResult[2]      }    }  }  
getResolution('1024x768');  {    width: '1024',    height: '768'  }  

多虧用了 ? 運算符,如果還有其他空格,它也將起作用:

getResolution('1920 x 1080');    {    width: '1920',    height: '1080'  }  

粘性標誌(sticky)

如你所見,RegExp 對象有一個名為 lastIndex 的屬性。當進行全局搜索(使用適當的標誌)時,可以在正確的位置繼續進行模式匹配。使用 ES6 中引入的 粘性標誌 y,我們可以強制從某個索引開始搜索。

function getDateFromString(dateString) {    const regexp = /([0-9]{2})-([0-9]{2})-([0-9]{4})/y;    regexp.lastIndex = 14;    const result = regexp.exec(dateString);    if(result){      return {        day: result[1],        month: result[2],        year: result[3]      }    }  }    getDateFromString('Current date: 14-05-2018');  

請記住,對字符串執行檢查(例如使用 exec)會更改 lastIndex 屬性,所以如果你希望它在多次粘性搜索之間保持不變,請不要忘記對其進行設置。如果模式匹配失敗,則將 lastIndex 設置為0。

注意:你可以檢查 RegExp 對象是否啟用了標誌。

const regexp = /([0-9]{2})-([0-9]{2})-([0-9]{4})/y;  regexp.lastIndex = 14;  console.log(regexp.sticky); // true  

其他標誌也是如此:更多相關的標誌,請訪問 MDN Web 文檔【https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/RegExp#RegExp_prototype_objects_and_instances】。

Unicode 標誌

ES6 也帶來了對 Unicode 的更好支持。添加 Unicode 標誌 u 可以啟用與 Unicode 相關的其他功能。多虧了它,你可以在模式中使用 u{x},其中 x 是所需字符的編碼。

/u{24}/u.test('$'); // true  

以上代碼如果沒有 u 標誌將會無法工作。重要的是要知道它的影響不僅限於此。如果不帶標誌,也可以處理一些的更特殊的 Unicode 字符:

/?/.test('?'); // true  

但這會在更複雜的情況下使我們失敗:

/a.b/.test('a?b');  // false  /a.b/u.test('a?b'); // true    /?{2}/.test('??');  // false  /?{2}/u.test('??'); // true    /[a?b]/.test('?');  // false  /[??]/u.test('?'); // true    /^[^x]$/.test('?');  // false  /[^x]/.test('?');    // true  /^[^x]$/u.test('?'); // true    /^[ab?]$/.test('?');  // false  /[ab?]/.test('?');    // true  /^[ab?]$/u.test('?'); // true  

我們可以很容易地得出一個結論,那就是在模式中包含 u 標誌是一種很好的做法,尤其是再可能含有除了標準 ASCII 之外的其他字符的情況。

如果將它與 忽略大小寫 標誌結合使用,則該模式也將同時匹配小寫和大寫字符。

/u{78}/ui.test('X'); // true  

有趣的是,在 HTML 中 input 和 textarea 元素的 pattern 屬性中,默認情況下啟用此標誌。

總結

今天,我們了解了有關 JavaScript 中的 RegExp 對象的更多信息,以及如何通過正則表達式的一個強大功能來運用這個知識:分組。我們還學習了兩個新標記:粘性和 Unicode。下次再見!

原文:https://wanago.io/2018/05/14/regex-course-part-three-grouping-and-using-es6-features/

下面夾雜一些私貨:也許你和高薪之間只差這一張圖

2019年京程一燈課程體系上新,這是我們第一次將全部課程列表對外開放。

願你有個好前程,願你月薪30K。我們是認真的 !

在公眾號內回復「體系」查看高清大圖

長按二維碼,加大鵬老師微信好友

拉你加入前端技術交流群

嘮一嘮怎樣才能拿高薪