講給前端的正則表達式(3):使用 ES6 特性

做者:wanago

翻譯:瘋狂的技術宅javascript

原文:https://wanago.io/2018/05/14/...html

未經容許嚴禁轉載前端

前文(點擊直達):java

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

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 屬性設置爲一個數字,該數字指示搜索中止的位置。es6

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

正則表達式中的分組

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

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階段的命名組提案,而且在上述用例中被證實是有幫助的。 Axel Rauschmayer 在 2ality 博客上的文章中對此進行了很好的描述。正則表達式

嵌套分組

你能夠嵌套分組:

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 文檔

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。下次再見!


本文首發微信公衆號:前端先鋒

歡迎掃描二維碼關注公衆號,天天都給你推送新鮮的前端技術文章

歡迎掃描二維碼關注公衆號,天天都給你推送新鮮的前端技術文章


歡迎繼續閱讀本專欄其它高贊文章:


相關文章
相關標籤/搜索