使用正则表达式解析表 - Java

Posted

技术标签:

【中文标题】使用正则表达式解析表 - Java【英文标题】:Parsing a table using regex - Java 【发布时间】:2016-03-31 07:33:58 【问题描述】:

我正在解析以下AWS 成本实例表:

m1.small    1   1   1.7     1 x 160    $0.044 per Hour
m1.medium   1   2   3.75    1 x 410    $0.087 per Hour
m1.large    2   4   7.5     2 x 420    $0.175 per Hour
m1.xlarge   4   8   15      4 x 420    $0.35 per Hour

有一个包含这些费用的文件:

input = new Scanner(file);
String[] values;
while (input.hasNextLine()) 
    String line = input.nextLine();
    values = line.split("\\s+"); // <-- not what I want...
    for (String v : values)
        System.out.println(v);

但是这给了我:

m1.small
1
1
1.7
1
x
160
$0.044
per
Hour

这不是我想要的...经过更正解析的values(使用正确的正则表达式)如下所示:

['m1.small', '1', '1', '1.7', '1 x 160', '$0.044', 'per Hour']

为了获得正确的结果,正确的regex 是什么?可以假设该表将始终具有相同的模式。

【问题讨论】:

实际数据是否用制表符分隔?是否存在列仅由一个空格分隔的情况? @Pietu1998 大多数情况下......但不一定......正则表达式会产生更强大的东西......这就是为什么我没有使用\\t+解析的原因。这些文件很大,因此搜索这些文件以修复丢失的选项卡可能毫无意义。 你能用\\s2,吗? @PM77-1 是的,但这给了我一个问题:1.7 1 x 160 $0.044 per Hour 换个方式怎么样?按\\s 拆分,然后连接部分结果。 【参考方案1】:

试试这个小提琴 https://regex101.com/r/sP6zW5/1

([^\s]+)\s+(\d+)\s+(\d+)\s+([\d\.]+)\s+(\d+ x \d+)\s+(\$\d+\.\d+)\s+(per \w+)

匹配文本,组就是你的列表。

我认为在您的情况下使用 split 太复杂了。如果文本总是相同的。就像字符串格式化的逆过程。

【讨论】:

啊,还有一件事……Javainvalid escape sequence 发脾气……我该如何解决?【参考方案2】:

如果你想使用正则表达式,你可以这样做:

        String s = "m1.small    1   1   1.7     1 x 160    $0.044 per Hour";
        String spaces = "\\s+";
        String type = "(.*?)";
        String intNumber = "(\\d+)";
        String doubleNumber = "([0-9.]+)";
        String dollarNumber = "([$0-9.]+)";
        String aXb = "(\\d+ x \\d+)";
        String rest = "(.*)";

        Pattern pattern = Pattern.compile(type + spaces + intNumber + spaces + intNumber + spaces + doubleNumber
                + spaces + aXb + spaces + dollarNumber + spaces + rest);
        Matcher matcher = pattern.matcher(s);
        while (matcher.find()) 
            String[] fields = new String[]  matcher.group(1), matcher.group(2), matcher.group(3), matcher.group(4),
                    matcher.group(5), matcher.group(6), matcher.group(7) ;
            System.out.println(Arrays.toString(fields));
        

请注意我是如何将正则表达式分解为可读的。 (作为一个长字符串,很难阅读/维护。)不过还有另一种方法。由于您知道要拆分哪些字段,因此您可以执行此简单拆分并使用组合值构建一个新数组:

        String[] allFields = s.split("\\s+");
        String[] result = new String[]  
            allFields[0], 
            allFields[1],
            allFields[2],
            allFields[3],
            allFields[4] + " " + allFields[5] + " " + allFields[6],         
            allFields[7], 
            allFields[8] + " " + allFields[9] ;
        System.out.println(Arrays.toString(result));

【讨论】:

【参考方案3】:

由一个或多个空格分割。并且空格必须出现在下面的上下文中。

数字 - 空格 - 不是“x”

不是“x” - 空格 - 数字

    values = line.split("(?<=\\d)\\s+(?=[^x])|(?<=[^x])\\s+(?=\\d)")));

【讨论】:

轰隆隆!非常感谢 @还有一件事......有些行有EBS Only $0.024,所以它也应该匹配......在这种情况下,['EBS Only', '$0.024'] ..我试图添加它但没有工作...

以上是关于使用正则表达式解析表 - Java的主要内容,如果未能解决你的问题,请参考以下文章

如何使用正则表达式从 PySpark databricks 笔记本中的文件中解析表名

使用 Java 正则表达式模式解析字符串?

Java中的String类下的正则表达式运用附带编程题解析

使用 Python 正则表达式解析 Java Arrays.deepToString 输出的浮点字符串

在多行上使用正则表达式进行 Html 解析

java解析xml ②之正则表达式配合解析