久久久久久久视色,久久电影免费精品,中文亚洲欧美乱码在线观看,在线免费播放AV片

<center id="vfaef"><input id="vfaef"><table id="vfaef"></table></input></center>

    <p id="vfaef"><kbd id="vfaef"></kbd></p>

    
    
    <pre id="vfaef"><u id="vfaef"></u></pre>

      <thead id="vfaef"><input id="vfaef"></input></thead>

    1. 站長資訊網(wǎng)
      最全最豐富的資訊網(wǎng)站

      正則基礎(chǔ)之 神奇的轉(zhuǎn)義

      1 概述
      這或許會是一個讓人迷惑,甚至感到混亂的話題,但也正因?yàn)槿绱耍庞辛擞懻摰谋匾?br />在正則中,一些具有特殊意義的字符,或是字符序列,被稱作元字符,如“?”表示被修飾的子表達(dá)式匹配0次或1次,“(?i)”表示忽略大小寫的匹配模式等等。而當(dāng)這些元字符被要求匹配其本身時,就要進(jìn)行轉(zhuǎn)義處理了。
      不同的語言或應(yīng)用場景下,正則定義方式、元字符出現(xiàn)的位置不同,轉(zhuǎn)義的方式也是林林總總,不一而同。
      2 .NET正則中的字符轉(zhuǎn)義
      2.1     .NET正則中的轉(zhuǎn)義符
      絕大多數(shù)語言中,“”都被作為轉(zhuǎn)義符,用來轉(zhuǎn)義一些具有特殊意義的字符或字符序列,比如“n”表示換行,“t”表示水平制表符等。而這樣的轉(zhuǎn)義,應(yīng)用到正則中,又會有一些意想不到的變化。
      話題由C#中一個正則問題引出

      復(fù)制代碼 代碼如下:
      string[] test = new string[]{“\”, “\\”};
      Regex reg = new Regex(“^\\$”);
      foreach (string s in test)
      {
           richTextBox2.Text += “源字符串: ” + s.PadRight(5, ‘ ‘) + “匹配結(jié)果: ” + reg.IsMatch(s) + “n”;
      }
      /*——–輸出——–
      源字符串:     匹配結(jié)果: True
      源字符串: \   匹配結(jié)果: False
      */

      對于這個結(jié)果,或許有人會感到迷惑,字符串中的“\”不是代表一個經(jīng)過轉(zhuǎn)義的“”字符嗎?而“\\”不就應(yīng)該代表兩個經(jīng)過轉(zhuǎn)義的“”字符嗎?那么上面正則匹配的結(jié)果應(yīng)該是第一個為False,第二個為True才對?。?br />對于這一問題,直接解釋或許不太容易理解,還是換種方式來解釋吧。
      比如要匹配的字符是這樣的
      string test = “(“;
      那么正則如何寫呢?因?yàn)椤?”在正則中是有特殊意義的,所以寫正則時必須對它進(jìn)行轉(zhuǎn)義,也就是“(”,而在字符串中,要使用“\” 來表示“”本身,也就是
      Regex reg = new Regex(“^\($”);
      這個如果理解了,那再把“(”換回“”,同樣道理,在字符串中,要使用“\” 來表示“”本身,也就是
      Regex reg = new Regex(“^\\$”);
      通過這樣的分析,可以看出,其實(shí)在以字符串形式聲明的正則中,“\\”匹配的實(shí)際上就是單獨(dú)的一個“”字符??偨Y(jié)一下它們之間的關(guān)系:
      輸出到控制臺或界面的字符串:
      程序中聲明的字符串:string test = “\”;
      程序中聲明的正則:Regex reg = new Regex(“^\\$”);
      這樣解釋是不是已經(jīng)可以理解了,那么是不是感覺這樣很笨拙?是的,在程序中以字符串形式聲明的正則,涉及到轉(zhuǎn)義符時就是這樣笨拙的。
      所以在C#中,還提供了另一種字符串聲明方式,在字符串前加個“@”,就可以忽略轉(zhuǎn)義。

      復(fù)制代碼 代碼如下:
      string[] test = new string[] { @””, @”\” };
      Regex reg = new Regex(@”^\$”);
      foreach (string s in test)
      {
          richTextBox2.Text += “源字符串: ” + s.PadRight(5, ‘ ‘) + “匹配結(jié)果: ” + reg.IsMatch(s) + “n”;
      }
      /*——–輸出——–
      源字符串:     匹配結(jié)果: True
      源字符串: \   匹配結(jié)果: False
      */

      這樣就簡潔多了,也符合通常的理解。
      但同時也帶來另一個問題,就是雙引號的轉(zhuǎn)義處理。在普通的字符串聲明中,可以用“””對雙引號進(jìn)行轉(zhuǎn)義。
      string test = “<a href=”www.test.com”>only a test</a>”;
      但是在字符串前加了“@”后,“”會被識別為“”字符本身,這樣就不能用“””對雙引號進(jìn)行轉(zhuǎn)義了,需要用“”””對雙引號進(jìn)行轉(zhuǎn)義。
      string test = @”<a href=””www.test.com””>only a test</a>”;
      而在VB.NET中,正則的定義只有一種形式,與C#中加了“@”后的定義方式是一致的。

      復(fù)制代碼 代碼如下:
      Dim test As String() = New String() {“”, “\”}
      Dim reg As Regex = New Regex(“^\$”)
      For Each s As String In test
          RichTextBox2.Text += “源字符串:” & s.PadRight(5, ” “c) & “匹配結(jié)果:” & reg.IsMatch(s) & vbCrLf
      Next
      ‘——–輸出——–
      ‘源字符串:    匹配結(jié)果:True
      ‘源字符串:\   匹配結(jié)果:False
      ‘——————–

      2.2     .NET正則中需要轉(zhuǎn)義的元字符
      在MSDN中,以下字符作為正則中的元字符,在匹配其本身時,需要對其進(jìn)行轉(zhuǎn)義
      . $ ^ { [ ( | ) * + ?
      但實(shí)際應(yīng)用中,還要根據(jù)實(shí)際情況來判斷,以上字符可能不需要轉(zhuǎn)義,也可能不止以上字符需要轉(zhuǎn)義。
      在正常的正則書寫過程中,以上字符的轉(zhuǎn)義通常都能被編寫人員正常處理,但是在動態(tài)生成正則時,就需要格外的注意,否則變量中包含元字符時,動態(tài)生成的正則在編譯時可能會拋異常。好在.NET中提供了Regex.Escape方法來處理這一問題。比如根據(jù)動態(tài)獲取的id來提取相應(yīng)的div標(biāo)簽內(nèi)容。
      string id = Regex.Escape(textBox1.Text);
      Regex reg = new Regex(@”(?is)<div(?:(?!id=).)*id=([‘””]?)” + id  + @”1[^>]*>(?><div[^>]*>(?<o>)|</div>(?<-o>)|(?:(?!</?divb).)*)* (?(o)(?!))</div>”);
      如果不做轉(zhuǎn)義處理,那么動態(tài)獲取的id如果為“abc(def”這種形式,程序運(yùn)行過程中就會拋出異常了。
      2.3     .NET正則中字符組的轉(zhuǎn)義
      在字符組[]中,元字符通常是不需要轉(zhuǎn)義的,甚至于“[”也是不需要轉(zhuǎn)義的。

      復(fù)制代碼 代碼如下:
      string test = @”the test string:  . $ ^ { [ ( | ) * + ? “;
      Regex reg = new Regex(@”[.$^{[(|)*+?\]”);
      MatchCollection mc = reg.Matches(test);
      foreach (Match m in mc)
      {
           richTextBox2.Text += m.Value + “n”;
      }
      /*——–輸出——–
      .
      $
      ^
      {
      [
      (

      )
      *
      +
      ?

      */

      但是在正則書寫時,字符組中的“[”還是建議使用“[”對其轉(zhuǎn)義的,正則本身就已經(jīng)是非常抽象,可讀性很低的了,如果在字符組中再摻雜進(jìn)這樣不經(jīng)轉(zhuǎn)義的“[”,會使得可讀性更差。而且在出現(xiàn)不正確的嵌套時,可能會導(dǎo)致正則編譯異常,以下正則在編譯時就會拋異常的。
      Regex reg = new Regex(@”[.$^{[(]|)*+?\]”);
      然而,.NET的字符組中,是支持集合減法的,在這種正常語法形式下,是允許字符組嵌套的。

      復(fù)制代碼 代碼如下:
      string test = @”abcdefghijklmnopqrstuvwxyz”;
      Regex reg = new Regex(@”[a-z-[aeiou]]+”);
      MatchCollection mc = reg.Matches(test);
      foreach (Match m in mc)
      {
           richTextBox2.Text += m.Value + “n”;
      }
      /*——–輸出——–
      bcd
      fgh
      jklmn
      pqrst
      vwxyz
      */

      這種用法可讀性很差,應(yīng)用也很少見,即使有這種需求也可以通過其它方式實(shí)現(xiàn),了解一下即可,不必深究。
      話題再回到轉(zhuǎn)義上,字符組中必須轉(zhuǎn)義的只有“”,而“[”和“]”出現(xiàn)在字符組中時,也是建議一定做轉(zhuǎn)義處理的。另外有兩個字符“^”和“-”,出現(xiàn)在字符組中特定位置時,如果要匹配其本身,也是需要轉(zhuǎn)義的。
      “^”出現(xiàn)在字符組開始位置,表示排除型字符組,“[^Char]”也就是匹配除字符組中包含的字符之外的任意一個字符,比如“[^0-9]”表示除數(shù)字外的任意一個字符。所以在字符組中,要匹配“^”字符本身,要么不放在字符組開始位置,要么用“^”進(jìn)行轉(zhuǎn)義。
      Regex reg1 = new Regex(@”[0-9^]”);
      Regex reg2 = new Regex(@”[^0-9]”);
      這兩種方式都表達(dá)匹配任意一個數(shù)字或普通字符“^”。
      至于“-”在字符組中特殊性,舉一個例子。

      復(fù)制代碼 代碼如下:
      string test = @”$”;
      Regex reg = new Regex(@”[#-*%&]”);
      richTextBox2.Text = “匹配結(jié)果:” + reg.IsMatch(test);
      /*——–輸出——–
      匹配結(jié)果:True
      */

      正則表達(dá)式中明明沒有“$”,為什么匹配結(jié)果會是“True”呢?
      []支持用連字符“-”連接兩個字符,來表示一個字符范圍。需要注意的是,“-”前后的兩個字符是有順序的,在使用相同的編碼時,后面的字符碼位應(yīng)大于或等于前面字符的碼位。

      復(fù)制代碼 代碼如下:
      for (int i = ‘#’; i <= ‘*’; i++)
      {
           richTextBox2.Text += (char)i + “n”;
      }
      /*——–輸出——–
      #
      $
      %
      &

      (
      )
      *
      */

      由于“#”和“*”符合要求,“[#-*]”可以表示一個字符范圍,其中就包含了字符“$”,所以上面的正則是可以匹配“$”的,如果只是把“-”當(dāng)作一個普通字符處理,那么要么換個位置,要么把“-”轉(zhuǎn)義。
      Regex reg1 = new Regex(@”[#*%&-]”);
      Regex reg2 = new Regex(@”[#-*%&]”);
      這兩種方式都表示匹配字符組中列舉的字符中的任意一個。
      在字符組中,還有一個比較特殊的轉(zhuǎn)義字符,“b”出現(xiàn)在正則表達(dá)式中一般位置時,表示單詞邊界,也就是一側(cè)為組成單詞的字符,另一側(cè)不是;而當(dāng)“b”出現(xiàn)在字符組中時,表示的是退格符,與普通字符串中出現(xiàn)的“b”意義是一樣的。
      同樣的,還有一個容易被忽視,而且經(jīng)常被忽視的轉(zhuǎn)義符“|”,當(dāng)“|”出現(xiàn)在正則表達(dá)式中一般位置時,表示左右兩側(cè)“或”的關(guān)系;而當(dāng)“|”出現(xiàn)在字符組中時,它僅僅表示“|”字符本身,沒有任何特殊意義,所以如果不是要匹配“|”本身,而試圖在字符組中使用“|”時,是錯誤的。比如正則表達(dá)式“[a|b]”表示的是“a”、“b”、“|”中的任意一個,而不是“a”或“b”。
      2.4     .NET正則應(yīng)用中不可見字符轉(zhuǎn)義處理
      對于一些不可見字符,要在字符串中表示時,需要用轉(zhuǎn)義字符,比較常見的有“r”、“n”、“t”等等,而這些字符在正則中應(yīng)用,就變得有些神奇了,先看一段代碼。

      復(fù)制代碼 代碼如下:
      string test = “one line. n another line.”;
      List<Regex> list = new List<Regex>();
      list.Add(new Regex(“n”));
      list.Add(new Regex(“\n”));
      list.Add(new Regex(@”n”));
      list.Add(new Regex(@”\n”));
      foreach (Regex reg in list)
      {
          richTextBox2.Text += “正則表達(dá)式:” + reg.ToString();
          MatchCollection mc = reg.Matches(test);
          foreach (Match m in mc)
          {
              richTextBox2.Text += ”   匹配內(nèi)容:” + m.Value + ”   匹配起始位置:” + m.Index + ”   匹配長度:” + m.Length;
          }
          richTextBox2.Text += ”   匹配總數(shù):” + reg.Matches(test).Count + “n—————-n”;
      }
      /*——–輸出——–
      正則表達(dá)式:
         匹配內(nèi)容:
         匹配起始位置:10   匹配長度:1   匹配總數(shù):1
      —————-
      正則表達(dá)式:n   匹配內(nèi)容:
         匹配起始位置:10   匹配長度:1   匹配總數(shù):1
      —————-
      正則表達(dá)式:n   匹配內(nèi)容:
         匹配起始位置:10   匹配長度:1   匹配總數(shù):1
      —————-
      正則表達(dá)式:\n   匹配總數(shù):0
      —————-
      */

      可以看到,前三種寫法,輸出的正則雖不同,但執(zhí)行結(jié)果卻是完全相同的,只有最后一種是沒有匹配的。
      正則表達(dá)式一Regex(“n”),其實(shí)就是以普通字符串形式來聲明正則的,與用Regex(“a”)來匹配字符“a”是同樣的道理,是不經(jīng)過正則引擎轉(zhuǎn)義的。
      正則表達(dá)式二Regex(“\n”),是以正則表達(dá)式形式來聲明正則的,正如正則中的“\\”就等同于字符串中的“\”一樣,正則中的“\n”就等同于字符串中的“n”,是經(jīng)過正則引擎轉(zhuǎn)義的。
      正則表達(dá)式三Regex(@”n”),與正則表達(dá)式二等價,是字符串前加“@”的寫法。
      正則表達(dá)式四Regex(@”\n”),其實(shí)這個表示的是字符“”后面跟一個字符“n”,是兩個字符,這個在源字符串中自然是找不到匹配項(xiàng)的。
      這里需要特別注意的還是“b”,不同的聲明方式,“b”的意義是不同的。

      復(fù)制代碼 代碼如下:
      string test = “one line. n another line.”;
      List<Regex> list = new List<Regex>();
      list.Add(new Regex(“lineb”));
      list.Add(new Regex(“line\b”));
      list.Add(new Regex(@”lineb”));
      list.Add(new Regex(@”line\b”));
      foreach (Regex reg in list)
      {
           richTextBox2.Text += “正則表達(dá)式:” + reg.ToString() + “n”;
           MatchCollection mc = reg.Matches(test);
           foreach (Match m in mc)
           {
                richTextBox2.Text += “匹配內(nèi)容:” + m.Value + ”   匹配起始位置:” + m.Index + ”   匹配長度:” + m.Length + “n”;
           }
           richTextBox2.Text += “匹配總數(shù):” + reg.Matches(test).Count + “n—————-n”;
      }
      /*——–輸出——–
      正則表達(dá)式:line_
      匹配總數(shù):0
      —————-
      正則表達(dá)式:lineb
      匹配內(nèi)容:line   匹配起始位置:4   匹配長度:4
      匹配內(nèi)容:line   匹配起始位置:20   匹配長度:4
      匹配總數(shù):2
      —————-
      正則表達(dá)式:lineb
      匹配內(nèi)容:line   匹配起始位置:4   匹配長度:4
      匹配內(nèi)容:line   匹配起始位置:20   匹配長度:4
      匹配總數(shù):2
      —————-
      正則表達(dá)式:line\b
      匹配總數(shù):0
      —————-
      */

      正則表達(dá)式一Regex(“lineb”),這里的“b”是退格符,是不經(jīng)過正則引擎轉(zhuǎn)義的。源字符串中是沒有的,所以匹配結(jié)果為0。
      正則表達(dá)式二Regex(“line\b”),是以正則表達(dá)式形式來聲明正則的,這里的“\b”是單詞邊界,是經(jīng)過正則引擎轉(zhuǎn)義的。
      正則表達(dá)式三Regex(@”lineb”),與正則表達(dá)式二等價,指單詞邊界。
      正則表達(dá)式四Regex(@”line\b”),其實(shí)這個表示的是字符“”后面跟一個字符“b”,是兩個字符,這個在源字符串中自然是找不到匹配項(xiàng)的。
      2.5     .NET正則應(yīng)用中其它轉(zhuǎn)義處理
      .NET正則應(yīng)用中還有一些其它轉(zhuǎn)義方式,雖然用得不多,但也順便提一下吧。
      需求:把字符串中“<”和“>”之間的數(shù)字前加上“$”

      復(fù)制代碼 代碼如下:
      string test = “one test <123>, another test <321>”;
      Regex reg = new Regex(@”<(d+)>”);
      string result = reg.Replace(test, “<$$1>”);
      richTextBox2.Text = result;
      /*——–輸出——–
      one test <$1>, another test <$1>
      */
      也許你會驚奇的發(fā)現(xiàn),替換結(jié)果不是在數(shù)字前加了“$”,而是將所有數(shù)字都替換為“$1”了。
      為什么會這樣呢,這是因?yàn)樵谔鎿Q結(jié)構(gòu)中,“$”是有特殊意義的,在它后面接數(shù)字,表示對對應(yīng)編號捕獲組匹配結(jié)果的引用,而有些情況下,需要在替換結(jié)果中出現(xiàn)“$”字符本身,但它后面又跟了數(shù)字,這時候就需要用“$$”對它進(jìn)行轉(zhuǎn)義了。而上面這個例子卻恰恰是由于這種轉(zhuǎn)義效果導(dǎo)致出現(xiàn)了異常結(jié)果,要規(guī)避這一問題,可以使替換結(jié)果中不出現(xiàn)對捕獲組的引用。
      string test = “one test <123>, another test <321>”;
      Regex reg = new Regex(@”(?<=<)(?=d+>)”);
      string result = reg.Replace(test, “$”);
      richTextBox2.Text = result;
      /*——–輸出——–
      one test <$123>, another test <$321>
      */

      3 JavaScript及Java中的轉(zhuǎn)義符
      JavaScript及Java中正則的轉(zhuǎn)義符處理,以字符串形式聲明時,基本上都是與.NET中一致的,簡單的介紹一下。
      在JavaScript中,以字符串形式聲明正則,與C#中的表現(xiàn)是一樣的,同樣會顯得很笨拙。

      復(fù)制代碼 代碼如下:
      <script type=”text/javascript”>
          var data = [“\”, “\\”];
          var reg = new RegExp(“^\\$”, “”);
          for(var i=0;i<data.length;i++)
          {
              document.write(“源字符串:” + data[i]  + ”   匹配結(jié)果:” + reg.test(data[i]) + “<br />”);
          }
      </script>
      /*——–輸出——–
      源字符串: 匹配結(jié)果:true
      源字符串:\ 匹配結(jié)果:false
      */

      JavaScript中雖然沒有提供C#中這種“@”方式的字符串聲明方式,但提供了另一種正則表達(dá)式的專有聲明方式。

      復(fù)制代碼 代碼如下:
      <script type=”text/javascript”>
          var data = [“\”, “\\”];
          var reg = /^\$/;
          for(var i=0;i<data.length;i++)
          {
              document.write(“源字符串:” + data[i]  + ”   匹配結(jié)果:” + reg.test(data[i]) + “<br />”);
          }
      </script>
      /*——–輸出——–
      源字符串: 匹配結(jié)果:true
      源字符串:\ 匹配結(jié)果:false
      */

      JavaScript中
      var reg = /Expression/igm;
      這種聲明方式,一樣可以簡化含有轉(zhuǎn)義符的正則。
      當(dāng)然,以這種形式聲明正則時,“/”自然也就成為了元字符,正則中出現(xiàn)這一字符時,必須進(jìn)行轉(zhuǎn)義處理。比如匹配鏈接中域名的正則
      var reg = /http://:([^/]+)/ig;
      很不幸的是,在Java中,目前只提供了一種正則聲明方式,也就是字符串形式的聲明方式

      復(fù)制代碼 代碼如下:
      String test[] = new String[]{“\”, “\\” };
      String reg = “^\\$”;
      for(int i=0;i<test.length ;i++)
      {
        System.out.println(“源字符串:” + test[i] + ”   匹配結(jié)果:” + Pattern.compile(reg).matcher(test[i]).find());
      }
      /*——–輸出——–
      源字符串:   匹配結(jié)果:true
      源字符串:\   匹配結(jié)果:false
      */

      只能期待Java的后續(xù)版本能提供這方面的優(yōu)化了。

      贊(0)
      分享到: 更多 (0)
      網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號