【问题标题】:How to search a string of key/value pairs in Java如何在 Java 中搜索一串键/值对
【发布时间】:2012-03-29 11:01:28
【问题描述】:

我有一个格式如下的字符串:

"key1=value1;key2=value2;key3=value3"

适用于任意数量的键/值对。

我需要检查某个键是否存在(假设它称为“特殊键”)。如果是这样,我想要与之关联的值。如果设置了多个“特殊键”,我只想要第一个。

现在,我正在寻找“specialkey”的索引。我从该索引开始获取一个子字符串,然后查找第一个 = 字符的索引。然后我寻找第一个; 字符的索引。这两个索引之间的子字符串给了我与“specialkey”相关的值。

这不是一个优雅的解决方案,它真的让我很困扰。找到与“specialkey”对应的值的优雅方法是什么?

【问题讨论】:

标签: java regex string-matching


【解决方案1】:

使用String.split:

String[] kvPairs = "key1=value1;key2=value2;key3=value3".split(";");

这将为您提供一个包含以下元素的数组kvPairs

key1=value1
key2=value2
key3=value3

遍历这些并拆分它们:

for(String kvPair: kvPairs) {
   String[] kv = kvPair.split("=");
   String key = kv[0];
   String value = kv[1];

   // Now do with key whatever you want with key and value...
   if(key.equals("specialkey")) {
       // Do something with value if the key is "specialvalue"...
   }
}

【讨论】:

    【解决方案2】:

    如果它只是您所追求的一键,您可以使用正则表达式 \bspecialkey=([^;]+)(;|$) 并提取捕获组 1:

    Pattern p = Pattern.compile("\\bspecialkey=([^;]+)(;|$)");
    Matcher m = p.matcher("key1=value1;key2=value2;key3=value3");
    
    if (m.find()) {
        System.out.println(m.group(1));
    }
    

    如果您正在使用其他键做某事,则在循环中拆分 ;= - 不需要正则表达式。

    【讨论】:

    • 请注意 string.split 的答案不仅是迟钝的,而且在您输入复杂性的第一个提示时它们开始分解(例如您需要一次匹配多个键,或者一个键没有其中的某个子字符串)。维护或更改也是一场噩梦,而这一点轻而易举。
    【解决方案3】:

    我会将字符串解析为映射,然后只检查键:

    String rawValues = "key1=value1;key2=value2;key3=value3";
    Map<String,String> map = new HashMap<String,String>();
    String[] entries = rawValues.split(";");
    for (String entry : entries) {
      String[] keyValue = entry.split("=");
      map.put(keyValue[0],keyValue[1]);
    }
    
    if (map.containsKey("myKey")) {
       return map.get("myKey");
    }
    

    【讨论】:

      【解决方案4】:

      以防万一有人对纯正则表达式方法感兴趣,以下 sn-p 有效。

      Pattern pattern = Pattern.compile("([\\w]+)?=([\\w]+)?;?");
      Matcher matcher = pattern.matcher("key1=value1;key2=value2;key3=value3");
      while (matcher.find()) {
         System.out.println("Key - " + matcher.group(1) + " Value - " + matcher.group(2);
      }
      

      输出将是

      Key - key1 Value - value1
      Key - key2 Value - value2
      Key - key3 Value - value3
      

      但是,正如其他人之前解释的那样,建议在任何一天使用String.split() 来执行此类任务。当有替代方法时,您不应该尝试使用 Regex 使您的生活复杂化。

      【讨论】:

        【解决方案5】:

        试试看:(?:(?:A=)([^,]*))

        演示:https://regex101.com/r/rziGDz/1

        否则,您使用正则表达式和您的列表找到代码以获得答案:

        import java.util.regex.Matcher;
        import java.util.regex.Pattern;
        import java.util.*;
            
        public class Main 
        {
            public static void main(String[] args) 
            {
              
            List<Integer> results = new ArrayList();
            Pattern pattern = Pattern.compile("(?:(?:A=)([^,]*))", Pattern.CASE_INSENSITIVE);
            List<String> OriginalList = Arrays.asList(
                    "A=1,B=2,C=3",
                    "A=11,B=12,C=13,D=15",
                    "A=5,B=4,C=9,D=10,E=13",
                    "A=19,B=20,C=91,D=40,E=33",
                    "A=77,B=27,C=37");
                    
                for (int i = 0; i < OriginalList.size(); i++) 
                {
                    Matcher matcher = pattern.matcher(OriginalList.get(i));
                    boolean matchFound = matcher.find();
                    if(matchFound) 
                    {
                        System.out.println( matcher.group(1) );
                        results.add( Integer.parseInt(matcher.group(1)) );
                    }
                }
            }
        }
        

        【讨论】:

          【解决方案6】:

          使用基本过滤器:使用[A-Z=,]+ 正则表达式进行拆分。选择第二个元素。

          public List filter() {
                  List<String> originalList = Arrays.asList("A=1,B=2,C=3", "A=11,B=12,C=13,D=15", "A=5,B=4,C=9,D=10,E=13",
                          "A=19,B=20,C=91,D=40,E=33", "A=77,B=27,C=37");
                  List<Integer> parsedData = new ArrayList();
                  
                  for(String str: originalList) {
                      Integer data = Integer.parseInt(str.split("[A-Z=,]+")[1]);
                      parsedData.add(data);
                      
                  }
                  return parsedData;
                  
          }
          

          【讨论】:

          • 您可以从您的角色类别中删除^。它仅适用于否定整个类,当它被放置为类中的第一个字符时,或者它被视为另一个字符。目前,字符串被拆分为:=^,。如果它没有在, 处拆分,则结果字符串数组中的第二个元素将是1,B,当尝试将其解析为Integer 时,这将导致java.lang.NumberFormatException。你可以用System.out.println(Arrays.toString(str.split("[=^,]")));检查我是否正确
          • str.split("[=^,]") 返回一个字符串数组,如 s[0]=A, s[1]=1, s[2]=B ... .从这个字符串数组中,我选择索引 1 的值并将其解析为整数)。在 github repo 中,我写了更多细节 -github.com/khabib97/StackOverflow-Responses/blob/main/…
          • 我知道它会返回什么。我尝试过这个。不带 ^ 试试。它返回完全相同的东西。 “和排除”究竟是什么意思?
          • 谢谢。这是我的错误。我更正了。
          【解决方案7】:

          试试这个:

          List<Integer> results = new ArrayList();
          
          Pattern p = Pattern.compile("(?:(?:A=)([^,]*))");
          Matcher m = null;
               
          for (String tmp : OriginalList) {
              m = p.matcher(tmp);
              if (m.find()) {
               int r = Integer.parseInt(m.group(0).replace("A=", ""));
                  results.add(r);
              }
                  
          }
          

          【讨论】:

          • 我想mMatcherpPatterncompile() 使用了什么正则表达式?您可以添加其余的代码吗?如果你能解释它也会有所帮助。 “试试这个”不是很有帮助。
          • 哦,是的!也许复制代码或合并某些东西会破裂。固定!
          • 请注意,这篇文章已合并到另一个问题中。也许您想更新它或添加与您的特定正则表达式相关的键/值。如果您解释了您正在使用的正则表达式,这也会有所帮助。当您使用group(1) 捕获值时,为什么要使用group(0) 然后删除A=
          【解决方案8】:

          有很多方法可以做到这一点。也许最简单的是使用 Streams API(Java 8 及更高版本可用)来处理匹配结果:

          List<String> OriginalList = Arrays.asList("A=1,B=2,C=3",
                  "A=11,B=12,C=13,D=15", "A=5,B=4,C=9,D=10,E=13",
                  "A=19,B=20,C=91,D=40,E=33", "A=77,B=27,C=37");
          
          • 这会流式传输字符串
          • 匹配模式并提取整数
          • 收集到列表
          Pattern p = Pattern.compile("A=(\\d+)");
          List<Integer> result = OriginalList.stream().
                  flatMap(str->p.matcher(str).results())
                  .map(mr->Integer.valueOf(mr.group(1)))
                  .collect(Collectors.toList());
          
          System.out.println(result);
          

          打印:

          [1, 11, 5, 19, 77]
          

          【讨论】:

          • Matcher::results 提供 Stream&lt;MatchResult&gt; 自 Java 9 起可用
          【解决方案9】:

          这可以使用 Stream API 来实现,方法是用逗号和Stream::flatMap简单地分割输入列表中的每个字符串

          // assuming A is not always at the beginning
          List<String> list = Arrays.asList(
                  "A=1,B=2,C=3",
                  "A=11,B=12,C=13,D=15",
                  "A=5,B=4,C=9,D=10,E=13",
                  "B=20,C=91,D=40,E=33",
                  "B=27, A=19, C=37, A=77");
          
          List<Integer> aNums = list.stream() // Stream<String>
              .flatMap(
                  s -> Arrays.stream(s.split("\\s*,\\s*")) // Stream<String> pairs of letter=digits
                             .filter(pair -> pair.startsWith("A="))
                             .map(pair -> Integer.valueOf(pair.substring(2)))
              )
              .collect(Collectors.toList());
          System.out.println(aNums);
          

          输出:

          [1, 11, 5, 19, 77]
          

          更新
          拆分输入字符串并仅保留与A 相关的数字的模式可以应用如下:

          Pattern splitByA = Pattern.compile("A\\s*=\\s*|\\s*,\\s*|[^A]\\s*=\\s*\\d+");
          List<Integer> aNums2 = list.stream()
              .flatMap(splitByA::splitAsStream) // Stream<String>
              .filter(Predicate.not(String::isEmpty)) // need to remove empty strings
              .map(Integer::valueOf)
              .collect(Collectors.toList());
          System.out.println(aNums2);
          

          输出是一样的

          [1, 11, 5, 19, 77]
          

          【讨论】:

            猜你喜欢
            • 2014-05-26
            • 2021-02-09
            • 1970-01-01
            • 2022-01-06
            • 2015-06-07
            • 1970-01-01
            • 2015-07-10
            • 2012-11-20
            相关资源
            最近更新 更多