string.replaceAll中的特殊字符
string.replaceAll(String regex, String replacement)中的replacement參數即替換內容中含有特殊字符 $ \ 時,需轉義。
- /*
- * 字符串"$ \"中的$與\字符互換位置
- */
- public class SpecialCharReplace {
- public static void main(String[] args) {
- String str = "$ \\";
- /*
- * string.replaceAll()中的特殊字符 $ 與 \
- *
- * 由於 $ 字符在作為替換內容時,是一個特殊字符,指反向引用前面的分組內容,所以把
- * 某字符替換成 $ 字符時,因該在前面加上轉義字符 \。
- * \ 字符就不用說了,本身就是轉義字符,但為什么在作為替換內容時要使用四個 \ 字符
- * ,這里又不是用在正則表達式里?這就是因為 \ 字符在作為替換內容里也是一個特殊字
- * 符,它用來將前面講的 $ 字符進行轉換的,所以也為特殊字符。以下是replaceAll的
- * 源碼片斷,從源碼就可以看出 \$ 是兩個特殊字符
- *
- * if (nextChar == '\\') {
- * cursor++;
- * nextChar = replacement.charAt(cursor);
- * result.append(nextChar);
- * cursor++;
- * } else if (nextChar == '$') {
- * // Skip past $
- * cursor++;
- * ...
- * }else {
- * result.append(nextChar);
- * cursor++;
- * }
- */
- System.out.println(str.replaceAll("\\$(\\W)\\\\", "\\\\$1\\$"));// \ $
- }
- }
Matcher對象的appendReplacement典型應用與特殊字符&\的進一步分析
問題的提出
字符串模板:
String template="尊敬的客戶${customerName}你好!本次消費金額${amount},您帳戶${accountNumber}上的余額為${balance},歡迎下次光臨!";
其中以 ${ 開始 } 結尾的為待替換的變量域。
數據存放於Map中,key為域名,value為域值。如:
Map--
customerName = 劉明
accountNumber = 888888888
balance = $1000000.00
amount = $1000.00
請編寫函數:
public static String composeMessage(String template, Map data) throw Exception
實現將任意模板字符串中的變量域,按域名替換為data中的域值。
例如,上例替換結果為:
"尊敬的客戶劉明你好!本次消費金額$1000.00,您帳戶888888888上的余額為$1000000.00,歡迎下次光臨!"
注:如果Map中找不到域值,以空字符串""替換。
問題的解決
- public class RegexExam {
- public static void main(String args[]) {
- HashMap data = new HashMap();
- String template = "尊敬的客戶${customerName}你好!本次消費金額${amount},"
- + "您帳戶${accountNumber}上的余額為${balance},歡迎下次光臨!";
- data.put("customerName", "劉明");
- data.put("accountNumber", "888888888");
- data.put("balance", "$1000000.00");
- data.put("amount", "$1000.00");
- try {
- System.out.println(composeMessage(template, data));
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- public static String composeMessage(String template, Map data)
- throws Exception {
- String regex = "\\$\\{(.+?)\\}";
- Pattern pattern = Pattern.compile(regex);
- Matcher matcher = pattern.matcher(template);
- /*
- * sb用來存儲替換過的內容,它會把多次處理過的字符串按源字符串序
- * 存儲起來。
- */
- StringBuffer sb = new StringBuffer();
- while (matcher.find()) {
- String name = matcher.group(1);//鍵名
- String value = (String) data.get(name);//鍵值
- if (value == null) {
- value = "";
- } else {
- /*
- * 由於$出現在replacement中時,表示對捕獲組的反向引用,所以要對上面替換內容
- * 中的 $ 進行替換,讓它們變成 "\$1000.00" 或 "\$1000000000.00" ,這樣
- * 在下面使用 matcher.appendReplacement(sb, value) 進行替換時就不會把
- * $1 看成是對組的反向引用了,否則會使用子匹配項值amount 或 balance替換 $1
- * ,最后會得到錯誤結果:
- *
- * 尊敬的客戶劉明你好!本次消費金額amount000.00,您帳戶888888888上的余額
- * 為balance000000.00,歡迎下次光臨!
- *
- * 要把 $ 替換成 \$ ,則要使用 \\\\\\& 來替換,因為一個 \ 要使用 \\\ 來進
- * 行替換,而一個 $ 要使用 \\$ 來進行替換,因 \ 與 $ 在作為替換內容時都屬於
- * 特殊字符:$ 字符表示反向引用組,而 \ 字符又是用來轉義 $ 字符的。
- */
- value = value.replaceAll("\\$", "\\\\\\$");
- //System.out.println("value=" + value);
- }
- /*
- * 經過上面的替換操作,現在的 value 中含有 $ 特殊字符的內容被換成了"\$1000.00"
- * 或 "\$1000000000.00" 了,最后得到下正確的結果:
- *
- * 尊敬的客戶劉明你好!本次消費金額$1000.00,您帳戶888888888上的
- * 余額為$1000000.00,歡迎下次光臨!
- *
- * 另外,我們在這里使用Matcher對象的appendReplacement()方法來進行替換操作,而
- * 不是使用String對象的replaceAll()或replaceFirst()方法來進行替換操作,因為
- * 它們都能只能進行一次性簡單的替換操作,而且只能替換成一樣的內容,而這里則是要求每
- * 一個匹配式的替換值都不同,所以就只能在循環里使用appendReplacement方式來進行逐
- * 個替換了。
- */
- matcher.appendReplacement(sb, value);
- System.out.println("sb = " + sb.toString());
- }
- //最后還得要把尾串接到已替換的內容后面去,這里尾串為“,歡迎下次光臨!”
- matcher.appendTail(sb);
- return sb.toString();
- }
- }