1. 程式人生 > >理解 Java 正則表示式怪異的 \\ 和 \\\\,讓您見怪不怪

理解 Java 正則表示式怪異的 \\ 和 \\\\,讓您見怪不怪

原文連線:http://unmi.cc/understand-java-regex-backslash/#more-2880

Java 語言裡的幾大變革,一為 jdk1.4 引入的正則表示式,jdk1.5 引入的泛型。沒有泛型之前有不少人曾想方設法從編譯器入手讓 Java 支援泛型。說到泛型  Perl 無疑是該方面的佼佼者,雖然我們不要求 Java 的正則表式能像 Perl 那樣可以用來寫詩,但至少能有 JavaScript 好用些,可是還不如。JavaScript 裡 // 兩斜線一框就是一個模式,分組和後向引用更方便,當然前面那兩傢伙是動態的,不太好比。

複雜的用法不說,且說 Java 的正則表示式在匹配點(.)  和斜槓(\),表示式要分別寫作 \\. 和 \\\\

,難看些,不好理解。幸好還有些人記住了,匹配點(.) 或  {、[、(、?、$、^ 和 * 這些特殊符號要要前加雙斜框,匹配 \ 時要用四斜槓,這確實能讓你包走天涯的。那麼為什麼是這樣呢,不是一個斜槓、三個或更多呢,所以知其然還要知其所以然,這樣才能每次心中有數,方能以一變應萬變。

用最簡單的例子來說明問題吧,不建立 Pattern、Matcher 等物件,就看 String 物件的 replaceAll(String regex, String replacement),它第一個引數接收的就是一個正則表示式,我們可以在 IDE 裡的偵錯程式中看 “a.b”.replaceAll(“.”,””) 能不能得到你期望的結果。

先說為什麼像點號(其他的特殊符號還有引號中的 “{、[、(、?、$、^ 和 *”)前面要加雙斜槓,注意逗號(,) 不是這一類特殊字元,因為它只會出現在中括號或花括號中。

顯然,如果直接執行

1 "a.b".replaceAll(".","");  //返回空字串

得到的值不是你想要的結果,成空字串了,因為點號 “.” 匹配了所有的字元,那要只匹配點號該如何呢,對的,雙斜槓

1 "a.b".replaceAll("\\.","");  //對的,得到的是 ab

那為什麼是雙斜槓呢?這個很簡單,因為點號(.),是個特殊字元,所以它前面需要需要加個斜槓給它轉義,你要真只用一個斜槓來轉義,問題就來了,提示你:

java regex slash

Invalid escape sequence (valid ones are \b \t \n \f \r \” \’ \\),也就是 Java 不認 \. 序列,所以還需要前面再加一道槓給其後的斜槓轉義出一個斜槓給點號(.) 用,也就是在 Java 字串看起來是 “\\.”, 但作為正則表示式來說就是 “\.”,這於其語言的正則表示式是一致的。

也就是說 Java 的正則表示式字串有兩層次的意義,那就是 Java 字串轉義出符合正則表示式語法的字串,“\\.”, 轉義後交給正則表示式的就是 “\.”,這是符合傳統的。因為我們平時字串轉義後直接用於輸出,所以帶來不少誤解,這裡的最終的正則表示式就是 Java 字串的輸出。

java regex slash 1

細心的同志一定能看到在偵錯程式裡的顯示,看我們寫成的“\\.”, 在偵錯程式裡顯示的是 “\\\\.”,說的是如果我們要得到 “\\.”,這樣的輸出那 Java 的字串就必須寫成 “\\\\.”, 兩個斜槓轉義出一個斜槓。

好的,理解了上面的由來,我們來看看用四個斜槓來匹配一個斜槓的原理。主要原因是斜槓 \ 本身就是用於轉義別的字元的,當然它的架子不是一般的大。因為正則表示式串就是 Java 字串的輸出,正常思維在正則表示式裡匹配斜槓用 “\\”, 那麼在 Java 程式裡向控制檯輸出 “\\”雙斜槓該如何寫呢,對了,就是 “\\\\”,就這麼簡單。

再一次從錯誤裡找下原因吧,假如我們寫成:

1 "a\\b".replaceAll("\", "");

報什麼錯呢?String literal is not properly closed by a double-quote,因為斜槓把其後的雙引號給轉義了,當然字串是未結束。再給它加個斜槓又如何呢?

1 "a\\b".replaceAll("\\", "");

Java 的語法是通過了,但是執行正則表示式不幹了,你轉義出來的交給正則表示式的一個斜槓,叫它情何以堪,該去轉義誰呢?所以執行時異常報 An exception occurred: java.util.regex.PatternSyntaxException

如果寫成三個斜槓呢?

1 "a\\b".replaceAll("<a>\\\</a>", ""); //與單個斜槓是一樣的異常,掛單的斜槓把雙引號給轉義了

所以這樣推來推去也是該寫成

1 "a\\b".replaceAll("<a>\\\\</a>", "");

對於正則表示式看到的就是 “\\”,哪種語言的正則表示式要的也是這個,也是第一個斜槓轉義了第二個,第三個轉義了第四個,最終就是 “\\”,正則表示式裡轉互相轉義一下就是 “\”了。

我原來理解還只是停留下轉義啊,再轉義的基礎上,隨著寫這篇才更加理解到其中要義的,才發現,原來 Java 的正則表示式和其他語言的正則表示式語言是統一的。只要記住一點,你要想的正則表示式字串是什麼,而正則表示式字串就是 Java 字串的的輸出結果,你就知道應該怎麼寫了

最後來看下 Eclipse 偵錯程式裡僅匹配單個斜槓時,IDE 裡顯示的有多瘋狂:

java_regex_slash_3.jpg

這讓你體驗到四個斜槓又何其多也。注:全文中的斜框標準意義上應該叫做反斜槓,在此就不作全文替換了。


相關推薦

理解 Java 表示式怪異的 \\ \\\\見怪不怪

原文連線:http://unmi.cc/understand-java-regex-backslash/#more-2880 Java 語言裡的幾大變革,一為 jdk1.4 引入的正則表示式,jdk1.5 引入的泛型。沒有泛型之前有不少人曾想方設法從編譯器入手讓 Java

Java表示式patternmatches

package com.lks.regex; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * * @author lks * @time 2016年6月6日下午11:02

Java表示式PatternMatcher的一般用法

一.方法說明: find()方法是部分匹配,在部分匹配時和完全匹配時返回true,匹配不上返回false。如果該匹配的串有組還可

JAVA表示式區分IPv4IPv6地址

PS*程式碼直接見第二部分: 一、進入正題前先說說JAVA正則表示式相關概念: 1、常用字元類: [abc] == a||b||c   [a-zA-Z] == 所有大小寫字母中的任意一個      [0-9A-Za-z] == 任意

Java表示式過濾、替換將一段文字中的英語單詞分別提取出並統計詞頻按詞頻排序。

最近在學習自然語言處理,在建立基礎標籤庫時,遇到一個需要提取語料中的英文單詞的工作,做好了現在來和大家分享下。 實現效果:讀取檔案內容,把其中的英文單詞提取出,並統計詞頻。提取時,原本不是連在一起的單詞可以分開獨立提取,例如:我的PPT和WORD,可以提取出PPT,WORD兩個單詞。 基本思

java表示式去除html中所有的標籤特殊HTML字元

關於java正則表示式去除html中所有的標籤和特殊HTML字元,結合我所做的專案總結的經驗: 總共分為三種:第一種適用於適用短的文章,將文章用正則表示式的方式拼接到程式碼中,有些繁瑣,其實不太實用。第二種就是直接將文件引入,進行更改,但是有一個小缺點,就是文件中的格式可能是utf-8格式的

表示式表示IP子網掩碼

一、IP地址的正則表示式 1、無任何判斷: /^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$/ 2、判斷0.0.0.0不符合IP書寫規範: /^(25[0-5]|2[

關於java表示式中的 ^$的使用

java正則表示式的邊界匹配符中,有兩個比較常用的字元:“ ^ ”和“ $ ”,這兩個字元理解起來比較容易混淆。先說下這兩個字元的含義: “ ^ ”:匹配輸入字串開始的位置。如果設定了 RegExp 物件的 Multiline 屬性,^ 還會與”\n”或”\r

java:表示式的概述簡單使用

public class Demo1_Regex { public static void main(String[] args) { // TODO Auto-generated method

Java表示式 常用

1匹配驗證-驗證Email是否正確 Java | 複製 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public static void main(String[] ar

Java表示式替換移除空行多餘的空格

這幾天重拾Java寫程式碼,需要操作文字檔案中的內容。 最終,要把內容裡的空行和多餘的連續空格移除,使用String裡的replace或者replaceAll,試了很多次都沒有成功。 最後發現需要使用正則表示式Regex。先把解決方案共享如下。 1. 移除多餘的連續空格,只

關於java表示式非捕獲型括號捕獲型括號的研究

        今天在做一個正則表示式的解析時,突然看見一個?:的例子,就看不懂了,然後在網上查了下,竟然是非捕獲型括號,意思就是匹配pattern,但不包含在match的group方法裡面。         (?:  pattern)是非捕獲型括號  匹配pattern,

HBase中過濾表示式JAVA表示式不一致問題的分析解決

HBase提供了豐富的查詢過濾功能。 比如說它提供了RegexStringComparator這樣的函式,可以實現按照正則表示式進行過濾。它可以有效地彌補向前綴查詢這樣的機制,從而可以使hbase也

表示式 匹配中文英文字母數字及_長度詳解

http://www.juapk.com/thread-2472-1-1.html 匹配中文:[\u4e00-\u9fa5]  英文字母:[a-zA-Z] 數字:[0-9] 匹配中文,英文字母和數字及_: ^[\u4e00-\u9fa5_a-zA-Z0-9]+

Java表示式之分組替換

正則表示式的子表示式(分組)不是很好懂,但卻是很強大的文字處理工具。 1 正則表示式熱身 匹配電話號碼 // 電話號碼匹配 // 手機號段只有 13xxx 15xxx 18xxxx 17xxx System.out.println("18304

表示式貪婪模式單詞邊界 多行模式表示式java版)

@Test public void test3(){ //參考部落格:http://blog.csdn.net/gnail_oug/article/details/51260216 /

Java表示式過濾出字母、數字中文

1、Java中過濾出字母、數字和中文的正則表示式 (1)過濾出字母的正則表示式 [^(A-Za-z)] (2) 過濾出 數字 的正則表示式 [^(0-9)] (3) 過濾出 中文 的正則表示式 [^(\\u4e00-\\u9fa5)] (4) 過濾出字母、數字

JAVA 表示式的三種模式: 貪婪, 勉強佔有的討論

    模式.*foo (貪婪模式):  模式分為子模式p1(.*)和子模式p2(foo)兩個部分. 其中p1中的量詞匹配方式使用預設方式(貪婪型)。  匹配開始時,吃入所有字元xfooxxxxxx去匹配子模式p1。匹配成功,但這樣以來就沒有了字串去匹配子模式p2。本輪匹配失敗;第二輪:減少p1部分的匹配量

Java表示式——驗證手機號電話號碼

一個朋友需要,所以寫了這兩個,話不都說,看程式碼 /** * 獲取當前的httpSession * @author :shijing * 2016年12月5日下午3:46:02 * @return */ public static HttpS

Java表示式Matcher的find()matches()方法不同

1、直接上結論: find()方法在部分匹配時和完全匹配時返回true,匹配不上返回false; matches()方法只有在完全匹配時返回true,匹配不上和部分匹配都返回false。 2、測試該結論的例子如下: String regex = "own\\.p