【问题标题】:Java Regex match to avoid splittingJava 正则表达式匹配以避免分裂
【发布时间】:2021-08-03 22:14:25
【问题描述】:

我正在读取一个包含多行的文本文件,如下所示。

key1:Combine(val -> [{"id":"123","pid":"Xd34d"},{"id":"124","pid":"sdDfsd"}])
key2:Combine(val -> [{"id":"211","pid":"Xd34d"},{"id":"223","pid":"sdDfsd"}])
key3:Combine(val -> [{"id":"423","pid":"Xd34d"},{"id":"454","pid":"sdDfsd"}])

对于每一行,我需要创建一个地图,其中包含 key 和 Json 字符串作为 val。

例如对于上面的例子,我需要我的地图是这样的

map1 = key1,{"id":"123","pid":"Xd34d"},{"id":"124","pid":"sdDfsd"}

map2 = key2,{"id":"211","pid":"Xd34d"},{"id":"223","pid":"sdDfsd"}

map3 = key3,{"id":"423","pid":"Xd34d"},{"id":"454","pid":"sdDfsd"}

我使用下面的拆分方法并剥离第二个 val 的最后 2 个字符。

String[] temp = str.split(":Combine(val -> [");

我正在尝试创建正则表达式模式匹配来提取这些我需要帮助的键和值

【问题讨论】:

    标签: java regex


    【解决方案1】:

    您将需要使用带有您需要的正则表达式的模式和匹配器,如下所示:

    Pattern pattern = Pattern.compile("val -> (.*)\\)");
    Matcher matcher = pattern.matcher(inputString);
    matcher.results().forEach((match) -> {
        System.out.println(match.group(1));
    });
    

    将输出:

    [{"id":"123","pid":"Xd34d"},{"id":"124","pid":"sdDfsd"}]
    [{"id":"211","pid":"Xd34d"},{"id":"223","pid":"sdDfsd"}]
    [{"id":"423","pid":"Xd34d"},{"id":"454","pid":"sdDfsd"}]
    

    要转换 Json,我只能推荐使用 Gson 并通过为它创建一个类来解析它,例如:

    Class GenericItem {
        Public Integer id;
        Public String pid;
    }
    
    Class ListOfGenericItems {
        List<GenericItem> items;
    }
    

    然后使用 gson 将结果变成更有用的东西:

    var key1 = new Gson.fromJson(match.group(1), ListOfGenericItems.class);
    

    这种方式如果你想使用你可以使用的数据

    key1.items(0).id; //get id of result of first group on key 1
    key1.items(1).pid; //get pid of result of second group on key 1
    

    @WJS 确实为正则表达式模式提供了更好的答案,但是,如果您想使用它来识别组的键,我的只会返回他们的 json 值,它们也会带来第一个键。

    【讨论】:

      【解决方案2】:

      使用拆分的替代方法:

      使用的正则表达式:

      "^(\\w+):Combine\\(val -> \\[(.*)\\]"
      

      根据上下文拆分:

      /**
       * Content of inputFile.txt:
       * key1:Combine(val -> [{"id":"123","pid":"Xd34d"},{"id":"124","pid":"sdDfsd"}])
       * key2:Combine(val -> [{"id":"211","pid":"Xd34d"},{"id":"223","pid":"sdDfsd"}])
       * key3:Combine(val -> [{"id":"423","pid":"Xd34d"},{"id":"454","pid":"sdDfsd"}])
       */
      public static void main(String[] args) throws IOException {
          String fileName = "C:\\Users\\myUserName\\Desktop\\inputFile.txt"; // windows file system
          List<String> linesFromInputFile = Files.readAllLines(Paths.get(fileName));
      
          Pattern replacePattern = Pattern.compile("^(\\w+):Combine\\(val -> \\[(.*)\\]");
          Pattern splitPattern = Pattern.compile("#");
      
          Map<String, String> mapResult = linesFromInputFile.stream()
                  .map(line -> replacePattern.matcher(line).replaceFirst("$1#$2"))
                  .map(replacedLine -> splitPattern.split(replacedLine))
                  .collect(Collectors.toMap(arr -> arr[0], arr -> arr[1]));
      
          // Print output
          mapResult.entrySet().stream()
                  .sorted(Comparator.comparing(Map.Entry::getKey))
                  .forEach(entry -> System.out.printf("Key: '%s' => Value: '%s'%n"
                          , entry.getKey()
                          , entry.getValue()));
      }
      

      输出:

      Key: 'key1' => Value: '{"id":"123","pid":"Xd34d"},{"id":"124","pid":"sdDfsd"})'
      Key: 'key2' => Value: '{"id":"211","pid":"Xd34d"},{"id":"223","pid":"sdDfsd"})'
      Key: 'key3' => Value: '{"id":"423","pid":"Xd34d"},{"id":"454","pid":"sdDfsd"})'
      

      【讨论】:

        【解决方案3】:

        这是许多可能的解决方案之一。

        String[] strs = {
                "key1:Combine(val -> [{\"id\":\"123\",\"pid\":\"Xd34d\"},{\"id\":\"124\",\"pid\":\"sdDfsd\"}])",
                "key2:Combine(val -> [{\"id\":\"211\",\"pid\":\"Xd34d\"},{\"id\":\"223\",\"pid\":\"sdDfsd\"}])",
                "key3:Combine(val -> [{\"id\":\"423\",\"pid\":\"Xd34d\"},{\"id\":\"454\",\"pid\":\"sdDfsd\"}])" };
        

        这是解析它的一种方法。您可以将其应用到流中,以便轻松构建地图。 keyvalue 最终会出现在下面的 group1group2 中。

        • (.*?): 勉强捕获字符直到第一个 :
        • .*?\\[ 不情愿地跳过字符直到并包括第一个 [
        • (.*}) 捕获剩余字符直到并包括最后一个 }
        
        String regex = "(.*?):Combine.*?\\[(.*})";
        Pattern p = Pattern.compile(regex);
        
        Map<String, String> results = Arrays.stream(strs)
                .flatMap(st -> p.matcher(st).results())
                .collect(Collectors
                        .toMap(m -> m.group(1), m -> m.group(2)));
        
        results.entrySet().forEach(System.out::println);
        

        打印

        key1={"id":"123","pid":"Xd34d"},{"id":"124","pid":"sdDfsd"}
        key2={"id":"211","pid":"Xd34d"},{"id":"223","pid":"sdDfsd"}
        key3={"id":"423","pid":"Xd34d"},{"id":"454","pid":"sdDfsd"}
        

        【讨论】:

        • 正则表达式看起来不错,但我想知道如果密钥本身有 : 怎么办
        • 我修改了我的答案以专注于正则表达式。我还包括了一个使用所述正则表达式构建地图的流解决方案。
        【解决方案4】:

        您表示您希望避免拆分,但在您的帖子中您展示了一个使用 split 的示例,所以我想我会通过以下方式解决这个问题。您可以使用交替 (|) 运算符拆分多个字符串。在以下情况下,拆分将生成大小为3 的数组。只有前两个值会用作键和值。

        String regex = ":Combine.*?\\[|(?:\\])";
        
        String s = 
          "key1:Combine(val -> [{\"id\":\"123\",\"pid\":\"Xd34d\"},{\"id\":\"124\",\"pid\":\"sdDfsd\"}])";
        
        String [] parts = s.split(regex);
        for (int i = 0; i < parts.length; i++) {
            System.out.printf("parts[%d] -> %s%n", i, parts[i]);
        }
        

        打印

        parts[0] -> key1
        parts[1] -> {"id":"123","pid":"Xd34d"},{"id":"124","pid":"sdDfsd"}
        parts[2] -> )
        

        并在流中使用来创建地图

        key1={"id":"123","pid":"Xd34d"},{"id":"124","pid":"sdDfsd"}
        key2={"id":"211","pid":"Xd34d"},{"id":"223","pid":"sdDfsd"}
        key3={"id":"423","pid":"Xd34d"},{"id":"454","pid":"sdDfsd"}
        
        
        Map<String, String> results = Arrays.stream(strs)
                .map(st -> st.split(regex))
                .collect(Collectors.toMap(a -> a[0], a -> a[1]));
        
        results.entrySet().forEach(System.out::println);
        

        打印

        key1={"id":"123","pid":"Xd34d"},{"id":"124","pid":"sdDfsd"}
        key2={"id":"211","pid":"Xd34d"},{"id":"223","pid":"sdDfsd"}
        key3={"id":"423","pid":"Xd34d"},{"id":"454","pid":"sdDfsd"}
        

        【讨论】:

          猜你喜欢
          • 2011-05-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-03-30
          • 2011-05-26
          相关资源
          最近更新 更多