Java 8 查找和替换匹配的字符串

4
我将尝试在errorMessage中查找来自messages.properties的字符串,如果errorMessage包含我需要的字符串,则需要用相应的值进行替换。
下面是我的messages.properties文件:
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

我的errorMessage可能是左侧字符串中的任何一个,我需要用右侧字符串值替换它。

以下是一些示例错误消息:

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

以下是我的方法,可以转换错误信息。
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;

}

以下是预期输出: 对于 errorMessage1 它工作得很好
System.out.println(toUserFriendlyErrorMessage(errorMessage1)); ==> Line 3 : Could not parse INVOICE DATE value 

但对于errorMessage2,它没有起作用。它没有将BaseRate替换为LINE ITEM UNIT COST

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

有没有一种方法可以查找多个字符串的出现并将其替换为相应的值?

例如:查找(BaseRate|Rate|tk_rate)并用LINE ITEM UNIT COST替换该字符串

我还想知道这种方法在Java 8中是否可以进一步简化?


1
为什么你的属性文件中没有BaseRate(还有另一个Rate和tk_rate)的条目?为什么要使用ResourceBundle(它应该有助于国际化),而不是java.util.Properties?为什么要使用带有正则表达式参数的replaceAll(),而不是只需要简单字符串的replace()? - JB Nizet
@JBNizet 我只想消除冗余,所以我尝试将BaseRate、Rate和tk_rate分组。另外,没有ResourceBundle,处理这个属性文件的更好方法是什么? - OTUser
1
就像我之前所说的:属性。消除冗余并没有带来显著的优势,反而会使你的代码变得更加复杂。让事情变得简单明了。 - JB Nizet
好的,我将为BaseRate、Rate和tk_rate设置单独的值。那么在Java 8中它可以进一步简化吗? - OTUser
1
我认为你应该重新考虑你的设计,并为几个“别名”使用单独的键。问题在于这些属性文件中的键不应包含空格——无论是否带括号——因此文件无法正确解析。如果你打印这些键,你会发现它们在第一个空格处被截断,例如(inv_start_date|invoice - tobias_k
@tobias_k 我明白了,我会改用 Map<String,String> 而不是文件。在Java 8中,这个方法能进一步简化吗? - OTUser
1个回答

4
我认为您应该重新考虑设计,并为几个“别名”使用单独的键 - 或者更好的方法是:根本不使用别名,只使用每个替换的一个键。问题在于这些属性文件中的键不应包含空格 - 无论是否带括号 - 因此文件无法正确解析。如果打印键,则会看到它们在第一个空格处被截断,例如 (inv_start_date|invoice start date) 变成了 (inv_start_date|invoice
当然,这也意味着,即使将这些“别名”分成单独的键,您也不能拥有像 invoice start date 这样的键,因为它仍然包含空格,无法正确解析。
您可以将这些替换放入 Java 源代码中的常规 Map 中。
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 ...
}

或者手动解析文件,通过在=处分割字符串并将其放入Map中。 由于像(BaseRate|Rate|tk_rate)这样的键实际上是有效的正则表达式,因此您可以使用replaceAll来替换它们的所有变体。如果它们不包含在字符串中,replaceAll将不会执行任何操作,因此contains检查实际上并不必要。
public static String toUserFriendlyErrorMessage(String message) {
    for (String key : replacements.keySet()) {
        message = message.replaceAll(key, replacements.get(key));
    }
    return message;
}

示例输出:

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

或者,如果你想使用一些“Java 8 魔法”,你可以使用 reduce,但个人认为循环更易读。

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接