代码之家  ›  专栏  ›  技术社区  ›  Alex

Java:如何根据提供的模式从字符串中提取值并将其填充到映射中?

  •  0
  • Alex  · 技术社区  · 7 年前

    我有两个字符串,一个是包含参数的模式,另一个是标题。

    我想从标题中提取参数值,并根据提供的模式将它们存储到地图中。模式中的参数以$作为前缀。

    例1:

    pattern = "home/$service/$source-$metadataId"
    title = "home/serviceA/test-ABC"
    

    然后,输出应该是一个包含以下所有键值对的映射:

    service = serviceA
    source = test
    metadataId = ABC
    

    例2:

    pattern = "home/$service/$source/$region/$year/$month/$day-$metadataId"
    title = "home/serviceA/test/NA/2019/3/3-ABC"
    

    然后,输出应该是一个包含以下所有键值对的映射:

    service = serviceA
    source = test
    region = NA
    year = 2019
    month = 3
    day = 3
    metadataId = ABC
    

    请告诉我是否有任何库可以在Java中实现这一点,或者您将如何在普通Java中实现这一点。

    注:

    1. 参数名称不包含任何特殊字符。(例如: (标点符号)
    2. 所有参数名称都以$
    0 回复  |  直到 7 年前
        1
  •  1
  •   Sibgha    7 年前

    据我所知,没有图书馆。这个问题在某些情况下非常特殊。但你可以编写自己的库来处理更多类似的情况。下面是一个Java小程序,它适用于您描述的所有情况(可以进一步扩展)。希望它能给你一些想法。

        String pattern = "home/$service/aaa/$source-$metadataId";
        String title = "home/serviceA/aaa/test-ABC";
    
        String patternNew = pattern.replaceAll("/\\$|-\\$", "/");
    
        // assuming both the strings contain same number of tokens.
        String[] keyTokens = (patternNew).split("/|-");
        String[] valueTokens = (title).split("/|-");
    
        Map<String, String> map = new HashMap<String, String>();
    
        for (int n = 1; n < keyTokens.length; n++) {
            String key = (keyTokens[n]);
            String value = (valueTokens[n]);
    
            if(key.equals(value))
                continue;
    
            map.put(key, value);
        }
    
        for (String name : map.keySet()) {
            System.out.print(name);
            System.out.print(" = " + map.get(name));
            System.out.println();
        }
    
        2
  •  0
  •   RedCam    7 年前
    String[] p = pattern.split("/\\$|-");
    String[] t = titlesplit("/|-");
    
     Map<String, String> map = new HashMap<>();
     for(int i=1; i<t.length; i++){
           map.put(p[i], t[i]);
      }
    
        3
  •  0
  •   Mikhail Vladimirov    7 年前
    1. 使用类似于 \$(\w+) 将模式拆分为文本块和占位符名称。对于第一个示例,您将获得以下文本块: "home/" , "/" , "-" , "" (最后一个区块是空字符串)和以下占位符名称: "service" , "source" , "metadataId" .
    2. 现在,从文本块构造正则表达式,如下所示: home/(.*)/(.*)-(.*) .别忘了正确引用文字块。
    3. 应用此正则表达式并获取捕获组的值: "serviceA" , "test" , "ABC" .
    4. 将在步骤1中收集的地图占位符名称与在步骤3中获得的捕获组值合并为地图占位符名称。
        4
  •  0
  •   nice_dev    7 年前
    import java.util.*;
    import java.io.*;
    public class Solution {
        public static void main(String[] args) throws IOException{
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            String pattern = br.readLine();
            String title = br.readLine();
            System.out.println(parseString(pattern,title).toString());
        }   
    
        private static Map<String,String> parseString(String pattern,String title){
            Map<String,String> map = new HashMap<>();
    
            String[] pat_tokens = pattern.split("/");
            String[] title_tokens = title.split("/");;
    
            for(int i=0;i<pat_tokens.length;++i){
                String[] sub_tokens = pat_tokens[i].split("\\-");
                String[] title_sub_tokens = title_tokens[i].split("\\-");
                for(int j=0;j<sub_tokens.length;++j){
                    if(sub_tokens[j].charAt(0) != '$') continue;
                    map.put(sub_tokens[j],title_sub_tokens[j]);
                }
            }       
    
            return map;
        }
    }
    

    你可以根据 / 等等 - 个人代币。如果字符串的起始字符不是 $ ,那么它就不是你想把它放在地图上的钥匙了。

        5
  •  0
  •   Sweeper    7 年前

    假设参数 价值观 (不仅仅是名称)只能包含单词字符,您可以执行以下操作:

    String pattern = "home/$service/$source/$region/$year/$month/$day-$metadataId";
    String title = "home/serviceA/test/NA/2019/3/3-ABC";
    String regex = "\\Q" + pattern.replaceAll("\\$(\\w+)", "\\\\E(?<$1>\\\\w+)\\\\Q") + "\\E";
    Matcher m = Pattern.compile(regex).matcher(title);
    if (m.find()) {
        Map<String, String> map = getNamedGroupCandidates(regex).stream().collect(Collectors.toMap(Function.identity(), m::group));
        System.out.println(map);
    }
    

    哪里 getNamedGroupCandidates 是从这个 post :

    private static Set<String> getNamedGroupCandidates(String regex) {
        Set<String> namedGroups = new TreeSet<>();
    
        Matcher m = Pattern.compile("\\(\\?<([a-zA-Z][a-zA-Z0-9]*)>").matcher(regex);
    
        while (m.find()) {
            namedGroups.add(m.group(1));
        }
    
        return namedGroups;
    }
    

    我基本上把你的“模式”转换成一个带有命名组的正则表达式。然后,我获取所有组名,并使用它们获取捕获的值。最后我把这些都放在一张地图上。