Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
452 views
in Technique[技术] by (71.8m points)

regex - Java 8 find and replace matching string(s)

I am trying to find a string from messages.properties in an errorMessage and if the errorMessage has the string I need to replace it with corresponding value

I have messages.properties as below

inv_date=INVOICE DATE
inv_id=INVOICE NUMBER
cl_id=CLIENT ID
lf_matter_id=LAW FIRM MATTER ID
inv_total_net_due=INVOICE TOTAL
(inv_start_date|invoice start date)=BILLING START DATE
(inv_end_date|invoice end date)=BILLING END DATE
inv_desc=INVOICE DESCRIPTION
units=LINE ITEM NUMBER OF UNITS
discount_amount=LINE ITEM ADJUSTMENT AMOUNT
total_amount=LINE ITEM TOTAL
(charge_date|charge date)= LINE ITEM DATE
acca_task=LINE ITEM TASK CODE
acca_expense=LINE ITEM EXPENSE CODE
acca_activity= LINE ITEM ACTIVITY CODE
(tk_id|time keeper id)=TIMEKEEPER ID
charge_desc=LINE ITEM DESCRIPTION
lf_id=LAW FIRM ID
(BaseRate|Rate|tk_rate)=LINE ITEM UNIT COST
tk_level=TIMEKEEPER CLASSIFICATION
cl_matter_id=CLIENT MATTER ID

My errorMesage can have any of the (left side)string and I need to replace it with right side string value

Below are couple of sample error messages

String errorMesage1 = "Line 3 : Could not parse inv_date value" 
String errorMesage2 = "Line : 1 BaseRate is a required field"

below is my method which conversts the error message

public static String toUserFriendlyErrorMessage(String message) {
    ResourceBundle rb = ResourceBundle.getBundle("messages");
    for(String key : rb.keySet()){
        String header = rb.getString(key);
        if(message.contains(key)) {
          return message.replaceAll(key, rb.getString(key));           
        }
    }
    return message;

}

Below is the expected output: for errorMessage1 it works fine

System.out.println(toUserFriendlyErrorMessage(errorMessage1)); ==> Line 3 : Could not parse INVOICE DATE value 

But for errorMessage2 its not working. It doesnt replace BaseRate with LINE ITEM UNIT COST

System.out.println(toUserFriendlyErrorMessage(errorMessage2)); ==> Line : 1 BaseRate is a required field

Is there a way to find the occurance of multiple strings and replace it with its corresponding value?

For example: Find (BaseRate|Rate|tk_rate) and replace the string with LINE ITEM UNIT COST

Also am wondering can this method simplified further in java 8?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I think you should reconsider your design and use individual keys for the several "aliases" - or probably even better: No aliases at all and just one key per replacement. The problem is that the keys in those properties files are not supposed to contain spaces -- parantheses or not -- so the files are not parsed correctly. If you print the keys, you will see that they are truncated at the first space, e.g. (inv_start_date|invoice start date) becomes (inv_start_date|invoice.

Of course, this also means that, even if you split those "aliases" into separate keys, you can not have keys like invoice start date, as it still contains spaces and will not be parsed correctly.

You could just put those replacements into a regualr Map in your Java source code:

static Map<String, String> replacements = new HashMap<>();
static {
    replacements.put("inv_date", "INVOICE DATE");
    replacements.put("(BaseRate|Rate|tk_rate)", "LINE ITEM UNIT COST");
    // ... more stuff ...
}

Or parse the file manually, splitting the strings at = and putting them into a Map.

And since keys like (BaseRate|Rate|tk_rate) are in fact valid regular expressions, you can just use replaceAll to replace them in all their variants. If they are not contained in the string, replaceAll will just do nothing, so the contains check is not really necessary.

public static String toUserFriendlyErrorMessage(String message) {
    for (String key : replacements.keySet()) {
        message = message.replaceAll(key, replacements.get(key));
    }
    return message;
}

Example output:

Line 3 : Could not parse INVOICE DATE value
Line : 1 LINE ITEM UNIT COST is a required field

Or, if you want to use some "Java 8 magic", you could use reduce, but personally, I think the loop is more readable.

    return replacements.keySet().stream()
            .reduce(message, (s, k) -> s.replaceAll(k, replacements.get(k)))
            .toString();

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...