【问题标题】:Regex: starts with messages and string between parent message curly brace正则表达式:以消息和父消息花括号之间的字符串开头
【发布时间】:2022-02-04 20:40:00
【问题描述】:

我想获取所有的消息数据。这样它应该在父消息的大括号之间查找消息和所有数据。使用下面的模式,我没有得到所有的父体。

 String data = "syntax = \"proto3\";\r\n" + 
            "package grpc;\r\n" + 
            "\r\n" + 
            "import \"envoyproxy/protoc-gen-validate/validate/validate.proto\";\r\n" + 
            "import \"google/api/annotations.proto\";\r\n" + 
            "import \"google/protobuf/wrappers.proto\";\r\n" + 
            "import \"protoc-gen-swagger/options/annotations.proto\";\r\n" + 
            "\r\n" + 
            "message Acc {\r\n" + 
            "    message AccErr {\r\n" + 
            "        enum Enum {\r\n" + 
            "            UNKNOWN = 0;\r\n" + 
            "            CASH = 1;\r\n" + 
            "        }\r\n" + 
            "    }\r\n" + 
            "    string account_id = 1;\r\n" + 
            "    string name = 3;\r\n" + 
            "    string account_type = 4;\r\n" + 
            "}\r\n" + 
            "\r\n" + 
            "message Name {\r\n" + 
            "    string firstname = 1;\r\n" + 
            "    string lastname = 2;\r\n" + 
            "}";
        List<String> allMessages = new ArrayList<>();
        Pattern pattern = Pattern.compile("message[^\\}]*\\}");
        Matcher matcher = pattern.matcher(data);
        while (matcher.find()) {
            String str = matcher.group();
            allMessages.add(str);
            System.out.println(str);
        }
    }
    

我希望在我的大小为 2 的字符串数组列表中得到如下响应。

allMessage.get(0) 应该是:

message Acc {
    message AccErr {
        enum Enum {
            UNKNOWN = 0;
            CASH = 1;
        }
    }
    string account_id = 1;
    string name = 3;
    string account_type = 4;
}

allMessage.get(1) 应该是:

message Name {
    string firstname = 1;
    string lastname = 2;
}

【问题讨论】:

标签: java regex string


【解决方案1】:

首先删除"message" 出现在行首之前的输入,然后在换行符上拆分,然后是"message"(在拆分中包含换行符,以便使用干预父消息的换行符):

String[] messages = data.replaceAll("(?sm)\\A.*?(?=message)", "").split("\\R+(?=message)");

live demo

如果您确实需要List&lt;String&gt;,请将结果传递给Arrays.asList()

List<String> = Arrays.asList(data.replaceAll("(?sm)\\A.*?(?=message)", "").split("\\R+(?=message)"));

第一个正则表达式匹配从 start 到但不包括以 message 开头的第一行,它被替换为空白(即删除)。分解:

  • (?sm) 打开标志 s,使 dot 也匹配换行符,m,使 ^$ 匹配每行的开始和结束
  • \\A 表示输入的开始
  • .*? .* 表示任意数量的任意字符(包括根据设置的s 标志的换行符),但添加? 会使这个不情愿,所以它匹配为few 个字符,同时仍然匹配
  • (?=^message) 是一个向前看,表示以下字符是行首,然后是"message"

详细解释请参阅regex101 live demo

"message" 后跟一个或多个换行序列时,拆分正则表达式匹配:

  • \\R+ 表示一个或多个换行序列(所有操作系统变体)
  • (?=message)向前看 表示以下字符是 "message"

详细解释请参阅regex101 live demo

【讨论】:

  • 感谢上述方法,我在单个字符串列表中获取所有数据。我想根据消息进行拆分。所以,通过上面的例子,我应该得到大小为 2 的数组列表。编辑问题。
  • @Maana 此代码生成 两个 字符串。请将我的代码复制粘贴到您的 IDE 中并尝试。您可以在链接的现场演示中看到它产生了 2 个字符串。 (自原始发布以来我进行了一些编辑,因此您可能没有使用我的答案的最新版本)
  • Bohemian:如果您不介意或任何参考链接,请您解释一下该模式的含义。
  • @Maana 说明
  • @Maana 再问一个问题! (告诉我它的链接——还有另一种完全适用于更复杂情况的方法,但它值得自己提出问题)
【解决方案2】:

为你的正则表达式试试这个。它锚定 message 作为行的开头,并使用正向前瞻来查找下一条消息或消息的结尾。

Pattern.compile("(?s)\r\n(message.*?)(?=(\r\n)+message|$)")
// or
Pattern.compile("(?s)\r?\n(message.*?)(?=(\r?\n)+message|$)")

也没有拆分、解析或管理嵌套大括号:)

https://regex101.com/r/Wa2xxx/1

【讨论】:

  • 但完整解决方案中的代码行数更多。
  • 加入匹配的组是'更多的代码行?'
  • 只是说使用Pattern的完整工作代码需要7行代码,但the entire operation can be done in one line
  • @Maana 我不记得 java 是否需要设置全局标志。另外,尝试将 \r 设为可选 \r?
  • @Maana 我看到您的文档不以; 结尾。我会解决的。
猜你喜欢
  • 2019-02-11
  • 2010-09-29
  • 1970-01-01
  • 2015-07-05
  • 1970-01-01
  • 1970-01-01
  • 2021-11-24
相关资源
最近更新 更多