package regex;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 注意,Matcher才是正則式的主要操作類,它裡麵包含了抽取替換最重要的方法.Pattern不是主要的類.
* replaceAll用來全部替換.replaceFirst或replaceEnd可以做遞迴替換.
*
* @author gaoyibo
*
*/
public class RegexAPITest {
public static final int TITLE_LEN = 50;
public static final int DESC_LEN = 80;
// u4e00-u9fa5表示中文,uFF00-uFFFF表示全形 其它表示一些特殊字元.
public static String regexStr = "{([u4e00-u9fa5A-Za-z0-9'",;.:?!、<>‘“,;。:?!<>:suFF00-uFFFF]*)}";
public static enum IdeaContentType {
TITLE, DESC1, DESC2, ACCESS_URL, SHOW_URL
}
/**
* 需求描述:admin中廣告搜尋,稽核線索搜尋,行業審核中需要用到替換預設關鍵詞. 替換的規則是:
* 1.對於title,如果替換後的長度超過50,對於desc1,desc2,如果替換後的長度超過80,則不做替換,使用預設關鍵詞並且顯示為綠色字型;
* 2.如果未超過,則使用指定的關鍵詞替換並且使用紅色字型.
*
* @author gaoyibo
* @param source
* 要替換的title or desc1 or desc2
* @param key
* 指定的關鍵詞
* @param type
* @return
*/
public static String replaceDefaultKey(String source, String key,
IdeaContentType type) {
String result = "";
if (source == null || source.length() <= 0)
return result;
Matcher matcher = Pattern.compile(regexStr).matcher(source);
if (!matcher.find()) {
return source;
}
String replaceFormatKey = "<font color='red'>" + key + "</font>";
// 先根據全部替換之後的值的長度判斷,如果超長,就不用[格式化後的key]去替換source裡面的預設關鍵詞.如果未超長,則替換.
result = Pattern.compile(regexStr).matcher(source).replaceAll(key);
switch (type) {
case TITLE:
// 不替換,使用預設關鍵詞,但預設關鍵詞要格式化
if (result.length() > TITLE_LEN) {
return doReplace(source);
}
// 替換
return matcher.replaceAll(replaceFormatKey);
case DESC1:
if (result.length() > DESC_LEN) {
return doReplace(source);
}
return matcher.replaceAll(replaceFormatKey);
case DESC2:
if (result.length() > DESC_LEN) {
return doReplace(source);
}
return matcher.replaceAll(replaceFormatKey);
default:
return source;
}
}
/**
* 遞迴方法,每次格式化第一個匹配到的預設關鍵詞.
*
* @author gaoyibo
* @param source
* @return
*/
public static String doReplace(String source) {
Matcher matcher = Pattern.compile(regexStr).matcher(source);
while (matcher.find()) {
// 匹配內容的提取.
String keytmp = matcher.group();
String defaultFormatKey = "<font color='green'>"
+ keytmp.substring(1, keytmp.length() - 1) + "</font>";
// 第一個匹配內容替換,替換之後,再遞迴.
return doReplace(matcher.replaceFirst(defaultFormatKey)); // 將當前的預設關鍵詞格式化之後,將返回的字串遞迴.直到所有的預設關鍵詞都被格式化.
}
return source;
}
public static void main(String[] args) throws IOException {
// 下面的字串裡面有多個預設關鍵詞的萬用字元,每個預設關鍵詞都不一樣.
String testStr = "asd:{重1:}23:{:}saA{d中ks1}asdadsa{DK2}asda{dk}sad2rty34";
System.out.println(replaceDefaultKey(testStr, "kkkkkk",
IdeaContentType.TITLE));
}
}
1. 在 java.util.regex 包中有哪三個公用的類?描述一下它們的作用。
2. 考慮一下字串“foo”,它的開始索引是多少?結束索引是多少?解釋一下這些編號的意思。
3. 一般字元和元字元有什麼不同?各給出它們的一個例子。
4. 如何把元字元表現成像一般字元那樣?
5. 附有方括弧的字元集稱為什嗎?它有什麼作用?
6. 這裡是三個預定義的字元類:d、s和w。描述一下它們各表示什嗎?並使用方括弧的形式將它們重寫。
7. 對於d、s和w,寫出兩個簡單的運算式,匹配它們相反的字元集。
8. 思考Regex(dog){3},識別一下其中的兩個子運算式。這個運算式會匹配什麼字串?
〖練習〗
1. 使用反向引用寫一個運算式,用於匹配一個人的名字,假設這個人的 first 名字與 last 名字是相同的。
【問題答案】
1. 問:在 java.util.regex 包中有哪三個公用的類?描述一下它們的作用。
答:
編譯後的 Pattern 執行個體表示Regex。
Matcher 執行個體是解析模式和靠著輸入的字串完成匹配操作的引擎。
PatternSyntaxException 定義一個未檢查異常,指示Regex中的語法錯誤。
2. 問:考慮一下字串“foo”,它的開始索引是多少?結束索引是多少?解釋一下這些編號的意思。
答:字串中的每一個字元位於其自身的儲存格中。索引位置在兩個儲存格之間。字串“foo”開始於索引 0,結束於索引 3,即便是這些字元僅佔用了 0、1 和 2 號儲存格。
3. 問:一般字元和元字元有什麼不同?各給出它們的一個例子。
答:Regex中的一般字元匹配其本身。元字元是一個特殊的字元,會影響被匹配模式的方式。字母A是一個一般字元。標點符號.是一個元字元,其匹配任意的單字元。
4. 問:如何把元字元表現成像一般字元那樣?
答:有兩種方法:
在元字元前加上反斜線();
把元字元置於Q(開始)E(結束)的參考資料表達式中。
5. 問:附有方括弧的字元集稱為什嗎?它有什麼作用?
答:是一個字元類。通過方括弧間的運算式,匹配指定字元類中的任意一個字元。
6. 問:這裡是三個預定義的字元類:d、s和w。描述一下它們各表示什嗎?並使用方括弧的形式將它們重寫。
答:d 匹配任一數字[0-9]
s 匹配任意空白字元[ tn-x0Bfr]
w 匹配任意單詞字元[a-zA-Z_0-9]
7. 問:對於d、s和w,寫出兩個簡單的運算式,匹配它們相反的字元集。
答:d D [^d]
s S [^s]
w W [^w]
8. 問:思考Regex(dog){3},識別一下其中的兩個子運算式。這個運算式會匹配什麼字串?
答:運算式由擷取的群組(dog)和接著的貪婪量詞{3}所組成。它匹配字串“dogdogdog”。
【練習答案】
1. 練習:使用反向引用寫一個運算式,用於匹配一個人的名字,假設這個人的 first 名字與 last 名字是相同的。
解答:([A-Z][a-zA-Z]*)s1
注釋返回目錄[1] 本文全文譯自 Java Tutorial 的 Regular Expressions,標題是譯者自擬的。——譯者注
[2] Unix 工具,用於檔案中的字串尋找,它是最早的Regex工具之一。——譯者注
[3] 若要退出可以使用 Ctrl + C 來中斷。——譯者注
[4] 圖中的“索引 3”指示是譯者所加,原文中並沒有。——譯者注
[5] 這種方式在 JDK 6.0 以前版本使用需要注意,在字元類中使用這種結構是有 bug 的,不過在 JDK 6.0 中已經修正。——譯者注
[6] 若E前沒有Q時會產生 PatternSyntaxException 異常指示語法錯誤。——譯者注
[7] 第一次匹配時僅匹配字串的開始部分,與A類似。(引自 Jeffrey E.F.Friedl, Mastering Regular Expressions, 3rd ed., §3.5.3.3, O'Reilly, 2006.)——譯者注
[8] u030A,即字元 å 上半部分的小圓圈( ̊ )(該字元在 IE 瀏覽器上無法正確顯示,在 Firefox 瀏覽器上可以正常地顯示)。——譯者注
[9] JDK 5.0 新增的方法,JDK 1.4 中不能使用。——譯者注
[10] JDK 1.4 和 JDK 5.0 適用的版本在所附的原始碼中。適用於 JDK 1.4 的檔案名稱為 RegexTestHarness2V4.java,JDK 1.5 的檔案名稱為 RegexTestHarness2V5.java。——譯者注
[11] 第三版是本書的最新版本。第三版的中譯本《精通Regex》已由電子工業出版社於 2007 年 7 月出版。——譯者注
發現appendReplacement與appendTail方法搭配也能起到上面遞迴方法的作用.如下例:
public static String doReplace2(String source) { Matcher matcher = Pattern.compile(regexStr).matcher(source); StringBuffer sb = new StringBuffer(); while (matcher.find()) { String keytmp = matcher.group(); String defaultFormatKey = "<font color='green'>" + keytmp.substring(1, keytmp.length() - 1) + "</font>"; matcher.appendReplacement(sb, defaultFormatKey); } matcher.appendTail(sb); return sb.toString(); }