ES6之 字符串和正則表達式


字符串和正則表達式

ES6 為我們增添幾個常用的字符串操作方法

  • includes() 方法。檢測指定文本,匹配到結果返回true,否則為false。可以用來替換indexOf來判斷字符串是否存在於另一個字符串中。

    • "abc".indexOf("a") > -1 => "abc".includes("a")

    • 當需要獲取字段的索引值時,只能依靠indexOf(或lastIndexOf),匹配到的索引值為字符串第一個字符在 另一個字符串中的位置。"abcd".indexOf("bc") //1

  • startsWith() 方法。在字符串的開始部分是否是以指定文本,是則返回true,反之為false。

  • endsWith() 方法。在字符串的結尾部分是否是以指定文本,是則返回true,反之為false。

    • 上面兩個方法均可接受兩個參數。以startsWith為例。

    • "abc".startsWith('b', 1) // true

      • 第一個參數為匹配文本

      • 第二個參數設置檢測的起始位置

      • endsWith中,第二個參數設置起始位置為 字符長度 - 參數值

  • repeat() 方法。接收一個number類型參數,表示改字符串的重復次數。

    • "ab".repeat(2) // abab

    • 若接收字符串可轉為數字。則進行隱式轉換。

    • 若接收字符串不可轉為數字。則返回空。


新增3個字符編碼的方法。

JavaScript的字符編碼方式為 UTF-16 進行構建,即用 16個 0 / 1的組合表示一個字符。
  • 編碼單元:這16個 0或1 的組合稱為一個編碼單元。

  • 基本多文種平面:編碼單元的取值范圍稱為基本多文中平面。

    • 基本多文種平面 -> Basic Multilingual Plane. (以下簡稱:BMP)
對於超出BMP的字符,16位編碼就無法表示了。為此UTF-16引入了代理對,用兩個16位編碼單元表示一個字符。
  • codePointAt() // 將字符轉換為字符編碼。

    • 對於BMP字符集中的字符,與charCodeAt()效果相同。

       "a".charCodeAt() // 97 
       "a".codePointAt() // 97
      
    • 對於非BMP字符集中的字符,會展示完整的字符編碼。

      •  "𠮷".charCodeAt()   // 55362
         "𠮷".charCodeAt(0)  // 55362  
         "𠮷".charCodeAt(1)  // 57271 
        
         "𠮷".codePointAt()  // 134071 
         "𠮷".codePointAt(0) // 134071 
         "𠮷".codePointAt(1) // 57271 
         "𠮷".codePointAt(2) // undefined  
        
      • 根據以上的代碼,我們可以知道,ES 5 中的charCodeAt()方法,對於非BMP字符集中的字符,只截取代理對中的第一段16位編碼,第二段則默認忽略。

      • 而ES 6新增的codePointAt()方法,很合理的使用了整個代理對來進行解析。且代理對的第二段作為輔助平面,而不做單獨解析。

    • 關於檢測一個字符占用的編碼單元數量,以下函數可提供參考。

        function is32Bit(c) {     
           return c.codePointAt(0) > 0xFFFF;  
        }  
        console.log(is32Bit("𠮷")) // true  
        console.log(is32Bit("a"))  // false
      
  • String.fromCodePoint() // 將字符編碼轉換為字符

    • 對於BMP字符集中的字符,與fromCharCode()效果相同。

      • String.fromCharCode(97) // a

      • String.fromCodePoint(97) // a

    • 對於非BMP字符集中的字符,fromCodePoint能展示更完整的字符。

      • String.fromCharCode(9731, 9733, 9842, 0x2F804) // ☃★♲

      • String.fromCodePoint(9731, 9733, 9842, 0x2F804) // ☃★♲你

  • normalize() // 統一標准化編碼的表示形式,通常在國際化應用中使用較多

    • 有很多歐洲國家的語言中有語調和重音符號。Unicode提供了兩種方法來進行編碼。

      • 一種是直接帶重音符號的字符 例如:Ǒ (\u01D1)

      • 另一種是合成符號:O (\u030C) 和 ̌(\u030C) 組成 Ǒ (\u01D1)

    • 兩種方式變現的字符相同,但字符並不相同 '\u01D1'==='\u004F\u030C' //false。ES 6新增的normalize(),能將Unicode正規化。可傳入四個可選值。

      • NFC。默認參數,按照標准等價分解,然后在以標准等價方式進行重組。

      • NFD。按照標准等價分解。

      • NFD。按照兼容等價分解。

      • NFKD。按照兼容等價分解,然后在以兼容等價方式進行重組。

      • 標准等價:視覺展示和語義上等價。

      • 兼容等價:語義等價、視覺展示不等價。

    • 在進行排序時,建議統一標准化進行處理。以下例子可供參考:

    • arr.sort(function(first, second) {   
           let firstNormalized = first.normalize(),        
                secondNormalized = second.normalize();    
           if (firstNormalized < secondNormalized) {        
               return -1;     
           } else if (firstNormalized === secondNormalized) {        
               return 0;    
           } else {        
               return 1;    
           }
       });
      

正則表達式的u修飾符

JavaScript的正則默認會將字符進行16位編碼處理,某些單個字符解析成兩個編碼。例如:"𠮷"
    let text = "𠮷";
    console.log(/^.$/.test(text));  // 匹配一個字符時得到 false  

ES 6加如了 u修飾符,使編碼操作處理變為按字符處理。

    let text = "𠮷";
    console.log(/^.$/.test(text)); // 匹配一個字符時得到 false
    console.log(/^.$/u.test(text)); // 匹配一個字符時得到 true
判斷瀏覽器JS解釋器是否支持正則中的 u修飾符,以下函數可提供參考:
  function hasExpU () {      
    try {          
      var pattern = new RegExp(",", u);          
         return true;      
    } catch (ex) { 
         return false;      
    }        
  }

正則表達式的y修飾符

正則采用y修飾符后,匹配將會從lastIndex屬性值的位置為起點開始匹配。若從lastIndex開始的字符匹配到結果,則返回true,否則為false。換種說法,以lastIndex值為起點,進行startsWith匹配。
    let text = "hello1 hello2 hello3",    
    pattern = /hello\d/y;    
    console.log(pattern.test(text)); // true
    pattern.lastIndex = 1;     // 初始化匹配起始位置
    console.log(pattern.test(text)); // false 
  • lastIndex = 1,即從"ello1 hello2 hello3"中匹配。正則中是以h開頭,與e不同,所以返回false。

  • 當y修飾符的正則匹配到結果后,lastIndex會更新為匹配到結果的最后一個索引值。再次正則匹配操作,會進行疊加,稱為粘滯行為。

  let text = "hello1 hello2 hello3",    
       pattern = /hello\d\s/y;    
  console.log(pattern.test(text));  // true
  console.log(pattern.test(text));  // true
  console.log(pattern.test(text));  // false (因為hello3后面無空格)
  • 注意:只有調用正則對象的方法才會涉及粘滯行為。test、exec等。而字符串的方法不會觸發,如match。
正則表達式的復制
  • 通過給RegExp構造函數傳遞第二個參數,可進行修飾符的覆蓋。
    let re1 = /abc/i,      
         re2 = new RegExp(re1, "g");        
    console.log(re2);  //   /abc/g 
正則的其他
  • flags 可獲取正則表達式的修飾符。
  let re1 = /abc/img;    
  console.log(re1.source);  // abc   (ES5 獲取正則表達式文本)  
  console.log(re1.flags);   // img   (ES6 獲取正則表達式修飾符)

模版字面量

模版字面量使用一對反引號表示( `` ),具有以下特點:
  • 支持字符串拼接

  • 支持換行

  • 支持空格記錄 (換行情況下)

  • 支持占位符 ( ${}, 且占位符中可以正常執行函數,表達式)

  • 標簽函數

對於ES 6之前的字符串拼接, '+' 和 '' 雖然能夠完成拼接,但變量插入,換行、空格記錄等十分繁瑣。ES 6 提供的模版字面量提高了這一方面的開發效率。
  let text = "test",    
       str = `This is     
       ${text} sentence!` ;
  console.log(str); 
  // This is    
      test sentence!
標簽函數:對模版字面量進一步處理的函數,放在反引號之前。
  • 標簽函數接收兩個參數,literals 和 ...substitutions。

  • 第一個參數是一個數組。以占位符為分割符號,分割元素組成的數組,累死split()函數分割后的返回值。

  • 第二個參數為 占位符的集合,是一種類數組結構,有length屬性

  let message = tag`hello world`; // tag 是我們自定義的一個標簽模版函數   
  function tag(literals, ...substitutions) {      
    // 內容  
  }

用法:模版處理、規避惡意腳本

  • 模版處理。先看下面的例子,例子中str變量正確的獲取了字符串。
  let a = 1, b = 2,      
       str = `${a} + ${b} = ${a + b}`;  
  console.log(str); // 1 + 2 = 3  

現在需求變成 '10 + 20 = 30',模版變成:

   str = `${a * 10} + ${b * 10} = ${a * 10 + b * 10}`; // 10 + 20 = 30

不免有些麻煩,模版較長時,維護起來並不容易。使用標簽函數試試。

  const a = 1, b = 2; 
  const str = strWork`${a} + ${b} = ${a + b}`;  
 
  function strWork(literals, ...substitutions) {   
    let result = '';   
    for (let i = 0; i < substitutions.length; i++) {     
      result += literals[i];
      result += String(Number(substitutions[i]) * 10);    
    }   
    return result; 
  } 

  console.log(str); // 10 + 20 = 30
  • 規避惡意腳本
  // 模板標簽過濾HTML字符串    
  function safeHTML(templateData) {      
    let s = templateData[0];      
    const args = arguments;      
    for (let i = 1, len = args.length; i < len; i++) {       
      let arg = String(args[i]);        // 特殊字符的替換        
      s += arg.replace(/&/g, "&").replace(//g, ">");        
      s += templateData[i];      
    }      
    return s;     
  }     
  const str = ' <&&&&';            
  console.log(safeHTML`hello world ${str}`);     // hello world <p> <&&&&

參考書籍:

《深入理解ES6》[美] NICHOLAS C. ZAKAS 著 劉振濤 譯


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM