【问题标题】:Regular Expression to extract label-value pairs in Java在 Java 中提取标签值对的正则表达式
【发布时间】:2008-12-25 19:44:35
【问题描述】:

我有一个文件包含几行类似于:

Name: Peter
Address: St. Serrano número 12, España
Country: Spain

而且我需要使用正则表达式提取地址,考虑到它可以包含点、特殊字符(ñ、ç)、áéíóú...

当前的代码可以运行,但是看起来很丑:。

Pattern p = Pattern.compile("^(.+?)Address: ([a-zA-Z0-9ñÑçÇáéíóú., ]+)(.+?)$",
                            Pattern.MULTILINE | Pattern.DOTALL);
Matcher m = p.matcher(content);
if (m.matches()) { ... }

编辑:地址字段也可以分成多行

Name: Peter
Address: St. Serrano número 12,   
Madrid
España
Country: Spain

编辑:我不能使用 Properties 对象或 YAML 解析器,因为该文件还包含其他类型的信息。

【问题讨论】:

    标签: java regex pattern-matching


    【解决方案1】:

    我不太了解 Java 的正则表达式对象,但类似这种模式的东西可以做到:

    ^Address:\s*((?:(?!^\w+:).)+)$
    

    假设多线和点状模式已开启。

    这将匹配以地址开头的任何行,后跟任何内容,直到换行符和一个单词,后跟一个冒号。

    如果您知道下一个字段必须是“国家/地区”,您可以稍微简化一下:

    ^Address:\s*((?:(?!^Country:).)+)$
    

    诀窍在于重复组中的前瞻断言。 '(?!国家:)。'将匹配除字符串 'Country:' 开头之外的所有内容,因此我们只需将其放在非捕获括号 (?:...) 中并用 + 对其进行量化,然后将所有这些分组到正常的捕获括号中。

    【讨论】:

    • 任何阅读此内容的人。对于多行情况,需要传递标志 DOTALL 并且需要从情况中删除 ^ 和 $。
    【解决方案2】:

    您可能想查看Properties 类而不是正则表达式。它为您提供了管理纯文本或 XML 文件以表示键值对的方法。

    因此您可以读取示例文件,然后在加载到Properties 对象后获取类似的值:

    Properties properties = new Properties();
    properties.load(/* InputStream of your file */);
    
    Assert.assertEquals("Peter", properties.getProperty("Name"));
    Assert.assertEquals("St. Serrano número 12, España", properties.getProperty("Address"));
    Assert.assertEquals("Spain", properties.getProperty("Country"));
    

    【讨论】:

    • 为什么使用 Apache Commons Assert 而不是 Java assert?
    【解决方案3】:

    假设“content”是一个包含文件内容的字符串,你的主要问题是你使用matches(),而你应该使用find()

    Pattern p = Pattern.compile("^Address:\\s*(.*)$", Pattern.MULTILINE);
    Matcher m = p.matcher(content);
    if ( m.find() )
    {
      ...
    }
    

    关于 MULTLINE 和 DOTALL 模式的其他答案似乎有些混乱。 MULTILINE 让^$ 锚分别匹配逻辑行的开头和结尾。 DOTALL 让点(句点、句号等)匹配行分隔符,如\n(换行)和\r(回车)。此正则表达式必须使用 MULTILINE 模式,不得使用 DOTALL 模式。

    【讨论】:

    • 谢谢。如果地址是多行字段怎么办?是否可以在不需要依赖下一个字段名称的情况下捕获它?
    • 如果地址字段位于输入的末尾,则尼克的两个正则表达式都将匹配。是这个意思吗?
    【解决方案4】:

    我并不是要陷入困境,但是您必须使用正则表达式吗?为什么不让未来的自己(或其他人)头疼,然后去做:

    String line = reader.readLine();
    while(line != null)
    {
        line = line.trim();
        if(line.startsWith("Address: "))
        {
            return line.substr("Address: ".length()).trim();
        }
        line = reader.readLine();
    }
    return null;
    

    当然,这也可以稍微参数化并放入方法中。

    否则,我会支持 Properties 或 JYaml 建议。

    【讨论】:

      【解决方案5】:

      不是 Java 人,但 "Address: (.*)$" 不工作吗?

      编辑:没有 Pattern.MULTILINE | Pattern.DOTALL 选项它应该只匹配该行。

      【讨论】:

        【解决方案6】:

        它可以包含换行符吗?如果它不能包含换行符,则不需要使用多行修饰符,而是可以这样做

        Pattern p = Pattern.compile("^Address: (.*)$");
        

        如果可以的话,我能想到的另一种选择是

        Pattern p = Pattern.compile("Address: (.*)\nCountry", Pattern.MULTILINE);
        

        如果没有 DOTALL,点将不会匹配换行符,因此您可以在正则表达式中明确指定它,让您可以按照您的要求进行操作。

        【讨论】:

          【解决方案7】:

          你一定要看看YAML

          你可以试试JYaml

          最重要的是它有多种语言的实现。

          ps 我已经尝试过YAML::XS 中的示例文本,效果很好。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-09-27
            • 2010-09-23
            • 2010-09-19
            • 1970-01-01
            相关资源
            最近更新 更多