String. replaceall and Java. Lang. illegalargumentexception
0. application scenarios (non-real applications, designed by the author)
During currency conversion, the unit of currency must be replaced according to the currency symbols of different countries. For example:
China: ¥
US: $
UK: Connecticut
The field indicating the currency unit is represented by a variable, for example, {curr }.
Replace the variable with the corresponding currency symbol according to the region settings.
1. Code
I wrote a very simple class to implement this function. The initial code is as follows:
Package Org. ly; </P> <p> Import Java. text. decimalformatsymbols; <br/> Import Java. util. locale; </P> <p> public class stringreplace {</P> <p> Public static void main (string [] ARGs) {<br/> string price = "{currency. symbol} 1000.00 "; <br/> decimalformatsymbols DFS = new decimalformatsymbols (locale. china); <br/> system. out. println ("the price is" + price. replaceall ("{currency. symbol} ", DFS. getcurrencysymbol (); <br/>}</P> <p>
2. Question 1
Execute the above class and the execution result is as follows:
Java. util. regEx. patternsyntaxexception: Illegal repetition <br/> {currency. symbol} <br/> at java. util. regEx. pattern. error (pattern. java: 1541) <br/> at java. util. regEx. pattern. closure (pattern. java: 2558) <br/> at java. util. regEx. pattern. sequence (pattern. java: 1669) <br/> at java. util. regEx. pattern. expr (pattern. java: 1558) <br/> at java. util. regEx. pattern. compile (pattern. java: 1291) <br/> at java. util. regEx. pattern. <init> (pattern. java: 1047) <br/> at java. util. regEx. pattern. compile (pattern. java: 785) <br/> at java. lang. string. replaceall (string. java: 1663) <br/> at ATIS. stringreplace. main (stringreplace. java: 13) <br/> exception in thread "Main"
When an exception or error occurs, there are two solutions:
A. Ask about Google and Baidu
Google searched for the keyword in the regular expression {And}, so escape is required.
B. debug it on your own.
In line 2558 of the Java. util. RegEx. pattern. closure method (the JDK used by the author is 1.4.2 _ 15), there is the following code:
Case '{': <br/> CH = temp [cursor + 1]; <br/> If (ASCII. isdigit (CH) {<br/> ...... <br/>} else {<br/> error ("illegal repetition"); <br/>}
That is, if the {symbol is displayed and the character following it is not a number, an exception is thrown.
In the JDK document, the keyword of the regular expression is also described as follows:
Greedy quantifiers
X? -X, once or not at all
X *-X, zero or more times
X +-X, one or more times
X {n}-X, EXACTLY n times
X {n,}-X, at least N times
X {n, m}-X, at least N but not more than m times
Reluctant quantifiers
X ?? -X, once or not at all
X *? -X, zero or more times
X ++? -X, one or more times
X {n }? -X, EXACTLY n times
X {n ,}? -X, at least N times
X {n, m }? -X, at least N but not more than m times
Possessive quantifiers
X? +-X, once or not at all
X * +-X, zero or more times
X ++-X, one or more times
X {n} +-X, EXACTLY n times
X {n ,}+-X, at least N times
X {n, m} +-X, at least N but not more than m times
Solution: Escape {And} and modify the replaceall code in the above class as follows:
System. Out. println ("the price is" + price. replaceall ("// {currency. symbol //}", DFS. getcurrencysymbol ()));
The running result is as follows:
The price is ¥1000.00.
3. Question 2
The above modification can make the program run normally, but to make the program run completely normally, all test cases should be passed.
Set locale to the United States. The output result is as follows:
The price is $1000.00.
Modify the class code:
Decimalformatsymbols DFS = new decimalformatsymbols (locale. China );
==>
Decimalformatsymbols DFS = new decimalformatsymbols (locale. US );
Run the program and get the following output:
Java. lang. stringindexoutofboundsexception: String Index out of range: 1 <br/> at java. lang. string. charat (string. java: 444) <br/> at java. util. regEx. matcher. appendreplacement (matcher. java: 559) <br/> at java. util. regEx. matcher. replaceall (matcher. java: 661) <br/> at java. lang. string. replaceall (string. java: 1663) <br/> at ATIS. stringreplace. main (stringreplace. java: 13) <br/> exception in thread "Main"
This time, through the Debug Method (I prefer this method. I often find problems and find and solve them myself to avoid similar errors next time, and I am quite impressed, of course, it is not necessary to spend too much time), you can find the problem is:
Java. util. regEx. matcher. appendreplacement (matcher. java: 559) <br/> while (cursor <replacement. length () {<br/> char nextchar = replacement. charat (cursor); <br/> If (nextchar = '//') {<br/> cursor ++; <br/> nextchar = replacement. charat (cursor); <br/> result. append (nextchar); <br/> cursor ++; <br/>} else if (nextchar = '$ ') {<br/> // skip past $ <br/> cursor ++; </P> <p> // The first number is always a group <br/> int refnum = (INT) replacement. charat (cursor)-'0'; <br/> If (refnum <0) | (refnum> 9 )) <br/> throw new illegalargumentexception (<br/> "illegal group reference"); <br/> cursor ++; </P> <p>
Here, the character/and $ are both processed as a special case. In this example, the string replaced by $ in the program will auto-increment the cursor, and the length of the string to be replaced will be 1, this causes arrayindexoutofboundsexception.
If we change the replacement character to "$ A", the exception becomes another one:
Java. Lang. illegalargumentexception: illegal group reference
Where the problem occurs, when the character is $, the cursor increases by 1. Then, if the ASCII value of the next character of $ is not 0 ~ The above exception is thrown.
The reason is that $ is also a special symbol in a regular expression. In the JDK documentation, it is described as follows:
Boundary matchers
^ The beginning of a line
$ The end of a line
Solution: escape the $ character. After escaping, the output can be correct.
3. Better Solution
As we all know, parameters such as {0} and {1} are often used in attribute files to replace messages during runtime. For example:
Errorcode = the input age value {0} is invalid. Age value must be a integer.
This is also a typical struts message method.
How does struts be replaced? Originally, Struts used the basic class java. Text. messageformat provided by JDK.
Messageformat can be constructed by passing in a string parameter (Message) and formatted by using the format (object) method. Here, the object can be passed in strings, string arrays, and so on.
In this way, the above class can be modified:
Package ATIS; </P> <p> Import Java. text. decimalformatsymbols; <br/> Import Java. text. messageformat; <br/> Import Java. util. locale; </P> <p> public class stringreplace {</P> <p> Public static void main (string [] ARGs) {<br/> string price = "the price is {0} 1000.00"; <br/> messageformat format = new messageformat (price ); <br/> decimalformatsymbols DFS = new decimalformatsymbols (locale. US); <br/> system. out. println (format. format (New String [] {DFS. getcurrencysymbol ()}); <br/>}< br/>4. Summary
This article mainly introduces two problems that may occur when you use string. replaceall. That is, the string. replaceall uses a regular expression internally, so you must be extremely careful about the keywords of the regular expression.
This section also describes how to replace parameters in messages in the Java. Text. messageformat class.