从可以采用多种形式并从 Java 中的 .properties 文件加载的字符串中提取值的最佳方法

Best Way to Extract Values from a String that can take many forms and is Loaded from a .properties file in Java

我有一个 ws.properties 文件,其中有一个名为 success.code 的 属性给我选择 HTTP 状态成功代码 (2xx) 的选项,除了默认的 200,我希望服务器也将其视为 "Success"。

思路是这样的:

  1. 如果我输入这样的值:

success.code=201,202, 203 (values separated by a comma)

负责提取这个值的代码部分应该立即明白这是三个独立的代码,提取它们中的每一个并将它们存储在列表或集合中或....

这其实很简单:

private Set<String[]> getSuccessCodes(HashMap<String, String> codes){
    Set<String[]> successCodes = new HashSet<>();
    String value;
    for (Map.Entry<String, String> entry : codes.entrySet()) {
        value = entry.getValue();
        if(!StringUtils.isEmpty(value))
            successCodes.add(value.split("\s*,\s*"));
    }
    return successCodes;
}
  1. 这里有点复杂:

我也想添加这些选项:

success.code=[202, 220] (two values written between hooks and separated by a comma)

success.code=2**

success.code=[200, 205], 22*

因此,根据我为成功代码输入的值,程序应该能够从中理解要做什么和要做什么 return。

这可以实现吗?

提前致谢

与其要求你的程序接受你定义的一些复杂的语法,为什么不让框架自然地做它做的事情呢?

success.codes = 201,202,203

success.code.min = 202 success.code.max = 220

success.code.prefix = 22

然后根据需要在您的代码中组合这些属性。这是实现你想要的最简单的方法。

首先,答案肯定是是可以实现的。解决方案是您将必须编写自己的解析器或迷你解释器来获取您的 String 并首先 "compile" 它 - 即检查它是否是有效输入(假设“[”的数量等于“]”的数量并且在解析“]”的数量时任何时候都不会大于“]”的数量,即字符串“[...]][”应该被宣布为无效)。然后它会解释它。您希望您的语言越灵活,您的口译员就会越复杂。很可能正则表达式是不够的。但一般来说,您需要编写一个带有如下签名的方法:

Set<Integer> parseHttpCodesParam(String input);

您的实施将有几条规则

  1. 如何处理逗号分隔的整数值
  2. 如何处理 []
  3. 中两个逗号分隔的数字
  4. 如何处理像 *
  5. 这样的特殊字符

等等

如果您不介意再添加三种方法,这里是一种方法:

  • 使用 "\s*,\s*(?![^\[]*\])" 拆分你的值,除非在括号中
  • 遍历结果数组并映射每个元素,检查它是否包含 [*
  • 如果它包含 [ 使用 [x,y] 中的值生成一个 IntStream.rangeClosed(x,y) 并将它们映射到它们的字符串值
  • 如果它包含 *,通过用 09 替换 * 生成一个 IntStream.rangeClosed(x00,x99),并将它们映射到它们的字符串值

类似于:

private static Set<String[]> getSuccessCodes(HashMap<String, String> codes){
    Set<String[]> successCodes = new HashSet<>();
    String value;
    for (Map.Entry<String, String> entry : codes.entrySet()) {
        value = entry.getValue();
        if(!StringUtils.isEmpty(value))
            successCodes.add(parse(value));
    }
    return successCodes;
}
public static String[] parse(String val) {
    String[] parts = val.split("\s*,\s*(?![^\[]*\])");
    return Arrays.stream(parts)
          .map(e -> e.contains("[")? getRangeCodes(e): e.contains("*")? getWildCCodes(e): e)
          .collect(Collectors.joining(",")).split("\s*,\s*");
}
private static String getRangeCodes(String e) {
    e = e.substring(1, e.length()-1);
    return IntStream.rangeClosed(Integer.parseInt(e.split("\s*,\s*")[0]), Integer.parseInt(e.split("\s*,\s*")[1]))
            .mapToObj(i -> String.valueOf(i))
            .collect(Collectors.joining(","));
}

private static String getWildCCodes(String e) {
    return IntStream.rangeClosed(Integer.parseInt(e.replace('*', '0')), Integer.parseInt(e.replace('*', '9')))
            .mapToObj(i -> String.valueOf(i))
            .collect(Collectors.joining(","));
}

测试:

public static void main(String[] args) { 
    HashMap<String, String> codes = new HashMap<>();
    codes.put("foo", "201, 202, 203");
    codes.put("bar", "[202, 220]");
    codes.put("baz", "2**");
    codes.put("doo", "[200, 205], 22*");
    codes.put("woo", "200, 201, 202, 203,[209, 214], 29*");

    Set<String[]> set = getSuccessCodes(codes);
    set.forEach(s -> {System.out.println(Arrays.toString(s));});
}