【问题标题】:Empty map generated while converting alphanumeric string to a map of numbers and strings将字母数字字符串转换为数字和字符串的映射时生成的空映射
【发布时间】:2018-10-18 05:03:24
【问题描述】:

以下代码 sn-p 用于将字母数字字符串划分为数字和字符串的映射,该映射作为来自 RestAPI 的响应正文参数。

String alphaNumericStr = "1XXGTE_FUSION2XXBIR_STALIO3XXVTE_CORE";
String regex = "[^a-zA-Z0-9']+";
Matcher matcher = Pattern.compile(regex).matcher(alphaNumericStr);

Map<Integer, String> map = new HashMap<>();
while (matcher.find()) {
    map.put(Integer.parseInt(matcher.group(1)), matcher.group(2));
}
System.out.println(map);

预期结果是

{1=XXGTE_FUSION, 2=XXBIR_STALIO, 3=XXVTE_CORE}

但我得到一张空地图。任何人都可以帮我解决这个问题。

【问题讨论】:

  • 问题是您的正则表达式中没有组。
  • XXGTE_FUSIONXXBIR_STALIO等可以包含数字吗?
  • @Wiktor 否。字符串使用数字分隔。

标签: java regex string pattern-matching


【解决方案1】:

您的代码应该抛出 java.lang.IndexOutOfBoundsException: No group 1,因为您尝试提取 matcher.group(1)matcher.group(2) 但您的正则表达式中没有它们。

相反,您可以使用此正则表达式:(\\d+)(\\D+) 匹配两个组,第一个匹配一个或多个数字,第二个匹配一个或多个非数字。

String alphaNumericStr = "1XXGTE_FUSION2XXBIR_STALIO3XXVTE_CORE";
String regex = "(\\d+)(\\D+)";
Matcher matcher = Pattern.compile(regex).matcher(alphaNumericStr);

Map<Integer, String> map = new HashMap<>();
while (matcher.find()) {
    map.put(Integer.parseInt(matcher.group(1)), matcher.group(2));
}
System.out.println(map);    

如果您使用的是 Java 9+,则可以使用:

Map<Integer, String> map = Pattern.compile(regex)
        .matcher(alphaNumericStr)
        .results()
        .collect(Collectors.toMap(
                m -> Integer.parseInt(m.group(1)), m -> m.group(2)
        ));

System.out.println(map);

输出

{1=XXGTE_FUSION, 2=XXBIR_STALIO, 3=XXVTE_CORE}

除了我微笑你在这里阅读这篇文章:Divide an alphanumeric string into a map of numbers and strings

【讨论】:

  • 感谢Java 9的方式,我不知道Collectors.toMap被添加了。
  • @SriHarshaChilakapati 诀窍在于results(),它返回Stream&lt;MatchResult&gt; ;)
  • 欢迎您@Aravinda Meewalaarachchi,如果这有助于您接受答案,请投票
【解决方案2】:

问题在于正则表达式。您的正则表达式不包含任何组,您正在尝试提取它们。

只需将正则表达式更改为以下内容。

String regex = "(\\d)([a-zA-Z_]+)";

这里的第一组 (\\d) 将匹配一个整数。第二组[a-zA-Z_]+ 将匹配由字母和_组合形成的任何字符序列。

String alphaNumericStr = "1XXGTE_FUSION2XXBIR_STALIO3XXVTE_CORE";
String regex = "(\\d)([a-zA-Z_]+)";
Matcher matcher = Pattern.compile(regex).matcher(alphaNumericStr);

Map<Integer, String> map = new HashMap<>();

while (matcher.find()) {
    map.put(Integer.parseInt(matcher.group(1)), matcher.group(2));
}

System.out.println(map);

现在可以解决这个问题了。

https://ideone.com/gZOhza

【讨论】:

    【解决方案3】:

    作为替代方案,您可以使用两个拆分调用来实现相同的目标(完全避免使用正则表达式 API):

    String text = "1XXGTE_FUSION2XXBIR_STALIO3XXVTE_CORE";
    
    String[] keys   = text.split("\\D+");
    String[] values = text.split("\\d+");
    
    Map<String, String> map = new HashMap<>();
    for (int i = 0; i < keys.length; i++) {
        map.put(keys[i], values[i + 1]); // +1 to skip the first blank
    }
    
    System.out.println(map);
    

    哪些打印:

    {1=XXGTE_FUSION, 2=XXBIR_STALIO, 3=XXVTE_CORE}
    

    【讨论】:

    • text.split 不使用regex 吗? :)
    • @notyou 需要一个正则表达式,但是这段代码没有使用正则表达式 API(MatcherPattern 等),它使用了String 类中的方法。跨度>
    • 啊,我知道,我的评论是开玩笑的。
    猜你喜欢
    • 2021-11-15
    • 2012-04-30
    • 1970-01-01
    • 2014-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-23
    相关资源
    最近更新 更多