RegEx for Complex String

时间:2017-09-13 20:13:33

标签: java regex

我是使用RegEx的新手,我正在尝试将其与Java引擎一起使用。我要解析的示例字符串如下:

name:"SFATG";affil:100;aup:1;bu:FALSE name:"SF TAC 1";affil:29.3478;aup:19;bu:FALSE name:"SF TAC 2";affil:22.2222;aup:14;bu:FALSE name:"SF TAC 3";affil:44.4444;aup:0;bu:FALSE name:"SF DISP 4";affil:82.4742;aup:0;bu:FALSE 

我希望RegEx实现的目标只是提取:之后和;之前出现的值。另外,我不想在name的条目中包含引号。但是,我(在这种特殊情况下)喜欢保留bu条目中显示的空格。但是,我不想为name的数据输入显示bu字段。所以我想要FALSE,而不是FALSE name这个字段。

使用此RegEx的最终目标是从所有组/数据值创建一个数组,以便该数组包含以下内容:

[0]: SFATG
[1]: 100
[2]: 1
[3]: FALSE 
[4]: SF TAC 1
...Etc.

我正在考虑为每个值创建组,因为我可以通过组合PatternMatcher类来轻松创建数组,这样:

String regEx = "Some really fancy RegEx that actually works";
Pattern p = Pattern.compile(regEx);
Matcher m = p.matcher("Some really really long String that follows the outlined format");
// I'd probably want to use an Object array since my data values vary by type
// I can also create 4 different arrays (one for name, another for affil, etc.),
// Any advice on which approach to take?
Object[] dataValues = new Object[m.groupCount()];

我到目前为止能够提出的RegEx如下:

name:"(\w+)";affil:(\d+);aup:(\d+);bu:(\w+\s)

但是,这似乎只对前4个数据值起作用,而且除此之外没有。

是否有人能够协助我为我正在使用的数据创建RegEx?对此的任何帮助将不胜感激!我也对任何有关如何处理此问题的想法持开放态度,例如使用不同的数据类型来存储数据(除了创建Object数组)。关键是以某种方式从我提到的字符串中获取数据值并存储它们以便稍后进行处理。

其他问题 我想可能有外部库可能更适合执行此任务。有人知道有一个适用于此的库吗?

2 个答案:

答案 0 :(得分:4)

一个正则规则来统治他们所有

\w+:(?:"([^"]+)"|(\d+)(?=;|\Z)|(\d+\.\d+)|([A-Z]+\s))

请参阅a demo on regex101.com

<小时/> 细分,这说:

\w+:                 # 1+ word characters, followed by :
(?:                  # a non-capturing group
    "([^"]+)"        # "(...)"
    |                # or
    (\d+)(?=;|\Z)    # only digits (no floats)
    |                # or
    (\d+\.\d+)       # floats
    |                # or
    ([A-Z]+\s)       # only UPPERCASE, followed by space
)

在这里,您需要查看哪个捕获组已填充,另外在Java中需要两个反斜杠(即。\\d+而不是\d+)。要检查哪个组匹配,您需要一些编程逻辑,例如 https://ideone.com/sbgZxY (我不是Java人。)

答案 1 :(得分:1)

虽然这个正则表达式比@ Jan的答案更不通用,但它确实限制了数据中字段的匹配,因此它将提供语法检查:

name:"([^"]+)";affil:([\d.]+);aup:(\d+);bu:(TRUE|FALSE) ?

关于提取值的方法,我创建了一个瘦包装器对象来提供类型安全性:

public class RowParser {
    private static final Pattern ROW_PATTERN = Pattern.compile("name:\"([^\"]+)\";affil:([\\d.]+);aup:(\\d+);bu:(TRUE|FALSE) ?");

    public static void main(String[] args) {
        String data = "name:\"SFATG\";affil:100;aup:1;bu:FALSE name:\"SF TAC 1\";affil:29.3478;aup:19;bu:FALSE name:\"SF TAC 2\";affil:22.2222;aup:14;bu:FALSE name:\"SF TAC 3\";affil:44.4444;aup:0;bu:FALSE name:\"SF DISP 4\";affil:82.4742;aup:0;bu:TRUE \n";
        System.out.println(parseRows(data));
    }

    public static List<Row> parseRows(String data) {
        Matcher matcher = ROW_PATTERN.matcher(data);
        List<Row> rows = new ArrayList<>();
        while (matcher.find()) {
            rows.add(new Row(matcher));
        }
        return rows;
    }

    // Wrapper object for individual data rows
    public static class Row {
        private String name;
        private double affil;
        private int aup;
        private boolean bu;

        Row(Matcher matcher) {
            this.name = matcher.group(1);
            this.affil = Double.parseDouble(matcher.group(2));
            this.aup = Integer.parseInt(matcher.group(3));
            this.bu = Boolean.parseBoolean(matcher.group(4));
        }

        public String getName() {
            return name;
        }

        public double getAffil() {
            return affil;
        }

        public int getAup() {
            return aup;
        }

        public boolean isBu() {
            return bu;
        }

        @Override
        public String toString() {
            return "name:\"" + name + '"' + ";affil:" + affil + ";aup:" + aup + ";bu:" + String.valueOf(bu).toUpperCase();
        }
    }
}