【问题标题】:Parsing files "/etc/default" using java使用 java 解析文件“/etc/default”
【发布时间】:2010-04-19 16:53:51
【问题描述】:

我正在尝试使用 java 和正则表达式解析通常在 /etc/default 中找到的配置文件。到目前为止,这是我在每个文件的每一行上迭代的代码:

// remove comments from the line
int hash = line.indexOf("#");
if (hash >= 0) {
    line = line.substring(0, hash);
}

// create the patterns
Pattern doubleQuotePattern = Pattern.compile("\\s*([a-zA-Z_][a-zA-Z_0-9]*)\\s*=\\s*\"(.*)\"\\s*");
Pattern singleQuotePattern = Pattern.compile("\\s*([a-zA-Z_][a-zA-Z_0-9]*)\\s*=\\s*\\'(.*)\\'\\s*");
Pattern noQuotePattern = Pattern.compile("\\s*([a-zA-Z_][a-zA-Z_0-9]*)\\s*=(.*)");

// try to match each of the patterns to the line
Matcher matcher = doubleQuotePattern.matcher(line);
if (matcher.matches()) {
    System.out.println(matcher.group(1) + " == " + matcher.group(2));
} else {
    matcher = singleQuotePattern.matcher(line);
    if (matcher.matches()) {
        System.out.println(matcher.group(1) + " == " + matcher.group(2));
    } else {
        matcher = noQuotePattern.matcher(line);
        if (matcher.matches()) {
            System.out.println(matcher.group(1) + " == " + matcher.group(2));
        }
    }
}

这按我的预期工作,但我很确定我可以通过使用更好的正则表达式来缩小这种方式,但我没有任何运气。有人知道读取这些类型文件的更好方法吗?

【问题讨论】:

    标签: java regex parsing properties


    【解决方案1】:

    您可以使用antlr 来生成解析器。基本上,您为要使用的语言编写语法(或使用众多grammars already written 之一,antlr 将为您生成解析器。

    【讨论】:

    • 我相信一个简单的正则表达式应该绰绰有余。我无法正确使用 (X|Y|Z) 构造并去除双引号或单引号。
    【解决方案2】:

    这是一个你可以使用的单一模式,它等同于你上面的三个:

    Pattern etcPattern = Pattern.compile(
       "\\s*([a-zA-Z_]\\w*)\\s*=\\s*"+
       "(\"|'|.{0,0})(.*?)\\2"+  //QUOTE MATCHING
       "\\s*");
    

    这和你的有三个不同之处:首先,我将表达式 [a-zA-Z0-9_] 替换为其预定义的字符类 \w(一个单词字符)。第二部分(QUOTE MATCHING)是一个模式,它将匹配和去除外部平衡引号,但也允许像您的三个模式那样不平衡引号。

    它以使用模式 (\"|'|.{0,0}) 开头。这是

    1. 双引号
    2. 单引号
    3. 任何零次

    然后你的 .* 模式后跟一个反向引用 \2。反向引用表示匹配模式 2(引用模式)匹配的内容。这就是上面第三种情况很重要的地方。如果该值不是以单引号或双引号开头,则需要能够忽略它。因此,它首先尝试匹配其中一个引号。如果不能,那么它将匹配空字符串,这反过来又允许反向引用匹配空字符串。

    使其工作的最后一个更改是将内部 .* 模式更改为不情愿(更改为 .*?),以便它允许引号在可能的情况下与反向引用匹配并被剥离。

    所以你应该可以这样运行:

    Matcher matcher = etcPattern.matcher(line);
    if (matcher.matches()) {
        System.out.println(matcher.group(1) + " == " + matcher.group(3));
    }
    

    相当于您上面的示例(请注意,该值现在在匹配组 3 中,而不是两个。正如我所说,这与您的模式所做的匹配,特别是它将允许不平衡的引号,并允许对值进行任何内部引用。

    【讨论】:

    • 太棒了……效果很好。这就是我这么喜欢的原因。伟大的人编写了伟大的代码。
    • 很高兴这是您正在寻找的,快速注意该模式确实允许不平衡的引号(我最初有一个错字说它没有,我已经修复了。)
    【解决方案3】:

    在很多情况下,您可以使用java.util.Properties 来处理shell 配置文件。

    实际上,如果您不让这些文件过于复杂,您可以通过这种方式在 shell 脚本和 java 程序之间共享它们。

    不能很好处理的是带引号的字符串。

    【讨论】:

    • 引用的字符串正是我遇到的问题。我可能会使用属性文件,然后检查值并删除引号,但这似乎很老套...
    猜你喜欢
    • 2021-05-01
    • 2013-12-24
    • 1970-01-01
    • 1970-01-01
    • 2019-08-14
    • 2015-03-02
    • 2015-07-10
    • 2015-08-25
    • 2011-12-15
    相关资源
    最近更新 更多