如何在 Java 中搜索一串键/值对

Posted

技术标签:

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

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

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

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

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

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

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

【问题讨论】:

请注意,这篇文章中的一些答案是从Extracting values corresponding to a certain "key" from a string List in Java 合并而来的,Arrays.asList("A=1,B=2,C=3","A=11,B=12,C=13,D=15",... 具有特定的键和值 【参考方案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/***-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]

【讨论】:

以上是关于如何在 Java 中搜索一串键/值对的主要内容,如果未能解决你的问题,请参考以下文章

Algolia:如何根据值对搜索进行排名?

如何比较输入文本中单词的长度并根据长度值对其进行排序

java - 如何在java中使用布尔值对ArrayLists进行排序?

多键值对搜索

Ajax的post表单,不在url后接一大串参数键值对的方法

Android-java-如何按对象内的某个值对对象列表进行排序