【问题标题】:Validate csv file with regular expression in Java在 Java 中使用正则表达式验证 csv 文件
【发布时间】:2012-11-10 00:36:23
【问题描述】:

文件结构如下:

"group","type","scope","name","attribute","value"
"c","","Probes Count","Counter","value","35"
"b","ProbeInformation","Probes Count","Gauge","value","0"

总是使用引号。还有一个尾随换行符。

这是我所拥有的:

^(\"[^,\"]*\")(,(\"[^,\"]*\"))*(.(\"[^,\"]*\")(,(\"[^,\"]*\")))*.$

匹配不正确。我正在使用 String.matches(regexp);

【问题讨论】:

  • 当然如何写出正确的 RE :)
  • 我认为你需要考虑像Says: "What?"这样的情况,如果你总是使用引号,那就是"Says: ""What?"""
  • 字段将没有" 字符。

标签: java regex csv


【解决方案1】:

免责声明:我什至没有尝试编译我的代码,但这种模式之前已经奏效了。

当我无法一眼看出正则表达式的作用时,我会将其分成几行,以便更容易弄清楚发生了什么。不匹配的括号更明显,您甚至可以向其中添加 cmets。另外,让我们在它周围添加 Java 代码,这样避免奇怪的事情就变得清晰了。

^(\"[^,\"]*\")(,(\"[^,\"]*\"))*(.(\"[^,\"]*\")(,(\"[^,\"]*\")))*.$

变成

String regex = "^" +
               "(\"[^,\"]*\")" +
               "(," +
                 "(\"[^,\"]*\")" +
               ")*" +
               "(." +
                 "(\"[^,\"]*\")" +
                 "(," +
                    "(\"[^,\"]*\")" +
                 ")" +
               ")*" +
               ".$";

好多了。现在开始做生意:我看到的第一件事是引用值的正则表达式。它不允许在字符串中使用逗号——这可能不是你想要的——所以让我们解决这个问题。让我们也把它放在它自己的变量中,这样我们就不会在某些时候输入错误。最后,让我们添加 cmets,以便我们可以验证正则表达式在做什么。

final String QUOTED_VALUE = "\"[^\"]*\""; // A double quote character, zero or more non-double quote characters, and another double quote
String regex = "^" +                           // The beginning of the string
               "(" + QUOTED_VALUE + ")" +      // Capture the first value
               "(," +                          // Start a group, a comma
                 "(" + QUOTED_VALUE + ")" +    // Capture the next value
               ")*" +                          // Close the group.  Allow zero or more of these
               "(." +                          // Start a group, any character
                 "(" + QUOTED_VALUE + ")" +      // Capture another value
                 "(," +                            // Started a nested group, a comma
                    "(" + QUOTED_VALUE + ")" +     // Capture the next value
                 ")" +                             // Close the nested group
               ")*" +                            // Close the group.  Allow zero or more
               ".$";                           // Any character, the end of the input

事情变得更加清晰。我在这里看到了两件大事:

1) (我认为)您正在尝试匹配输入字符串中的换行符。我会一起玩,但是在换行符上拆分输入比你正在做的更干净、更容易(不过,这是一个你可以自己做的练习)。您还需要注意不同操作系统具有的不同换行约定 (read this)。

2) 你捕捉的太多了。您想使用非捕获组或解析输出会很困难且容易出错 (read this)。

final String QUOTED_VALUE = "\"[^\"]*\""; // A double quote character, zero or more non-double quote characters, and another double quote
final String NEWLINE = "(\n|\n\r|\r\n)";  // A newline for (almost) any OS: Windows, *NIX or Mac
String regex = "^" +                           // The beginning of the string
               "(" + QUOTED_VALUE + ")" +   // Capture the first value
               "(?:," +                       // Start a group, a comma
                 "(" + QUOTED_VALUE + ")" + // Capture the next value
               ")*" +                       // Close the group.  Allow zero or more of these
               "(?:" + NEWLINE +            // Start a group, any character
                 "(" + QUOTED_VALUE + ")" +   // Capture another value
                 "(?:," +                       // Started a nested group, a comma
                    "(" + QUOTED_VALUE + ")" +  // Capture the next value
                 ")" +                          // Close the nested group
               ")*" +                         // Close the group.  Allow zero or more
               NEWLINE + "$";                 // A trailing newline, the end of the input

从这里,我看到你再次重复工作。让我们解决这个问题。这也修复了原始正则表达式中缺少的 *。看看能不能找到。

final String QUOTED_VALUE = "\"[^\"]*\""; // A double quote character, zero or more non-double quote characters, and another double quote
final String NEWLINE = "(\n|\n\r|\r\n)";  // A newline for (almost) any OS: Windows, *NIX or Mac
final String LINE = "(" + QUOTED_VALUE + ")" +   // Capture the first value
                    "(?:," +                       // Start a group, a comma
                      "(" + QUOTED_VALUE + ")" + // Capture the next value
                    ")*";                        // Close the group.  Allow zero or more of these
String regex = "^" +             // The beginning of the string
               LINE +            // Read the first line, capture its values
               "(?:" + NEWLINE + // Start a group for the remaining lines
                 LINE +            // Read more lines, capture their values
               ")*" +            // Close the group.  Allow zero or more
               NEWLINE + "$";    // A trailing newline, the end of the input

这更容易阅读,不是吗?现在,如果它不起作用,您可以分段测试您的大讨厌的正则表达式。

您现在可以编译正则表达式、获取匹配器并从中获取组。不过,您仍然有一些问题:

1) 我之前说过,换行更容易换行。一个原因是:你如何确定每行有多少个值?硬编码它会起作用,但一旦你的输入发生变化,它就会中断。也许这对您来说不是问题,但这仍然是不好的做法。另一个原因:正则表达式仍然太复杂,我不喜欢。你真的可以在 LINE 停下来。

2) CSV 文件允许这样的行:

"some text","123",456,"some more text"

要处理此问题,您可能需要添加另一个获取引用值或数字列表的迷你正则表达式。

【讨论】:

  • 与您一起行走时非常有帮助。我只对验证生成 csv 的一些代码的输出感兴趣。每行的字段数保证是恒定的,并且" 始终存在。你的代码做得非常好,谢谢。
  • 这是一种解脱!在这种情况下,您可以通过将所有组设为非捕获来加快速度。
【解决方案2】:

这个问题:CSV Parsing in Java 指向一个Apache library for parsing CSV

如果您的格式确实是 CSV,那么正则表达式将很难将数据解析为记录。

我知道这并不能直接回答您的问题,通过使用 CSV 库,您可能会事半功倍。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-04
    • 1970-01-01
    • 1970-01-01
    • 2011-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多