复杂字符串的正则表达式

3

我是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 

我希望正则表达式能够仅提取出出现在:;之间的值。此外,我不想在name条目中包含引号。然而,在这种非常特殊的情况下,我希望保留bu条目中出现的空格。但是,我不想让bu的数据条目中出现name字段。因此,对于这个字段,我想要的是FALSE,而不是FALSE name
我的最终目标是使用这个正则表达式创建一个数组,该数组将包含以下内容:
[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()];

我能提供的正则表达式如下:

我目前能想到的正则表达式如下:

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

然而,这似乎只适用于前4个数据值,其他的都不行。请问有谁能帮我创建一个适用于我正在处理的数据的正则表达式吗?非常感谢任何对此的帮助!如果有其他方法可以解决这个问题,比如使用不同的数据类型来存储数据(而不是创建对象数组),我也很愿意尝试。关键是要以某种方式从我提到的字符串中获取数据值,并将它们存储起来以备后续处理。
额外问题:我想象中可能会有更适合执行此任务的外部库。是否有人知道适用于此的库?

1
这个对我有效:name:“([^”]+)”;affil:([\d.])+;aup:(\d+);bu:(TRUE|FALSE)? - teppic
@teppic,这也非常接近了...然而,对于“affil”字段的第二组,只捕获浮点数中的一个数字(似乎只是最后一个数字)。 - coolDude
1
抱歉... + 需要在捕获组内部:即 affil:([\d.]+); - teppic
@teppic,如果您提供了带有调整后的正则表达式的答案,我将接受它。您的正则表达式正是我要找的,谢谢! - coolDude
我已将我的正则表达式添加为答案。 - teppic
我同意你对@Jan回答的评论。感谢你对此做出的贡献! - coolDude
2个回答

4

一种正则表达式来统治它们所有

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

请查看 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的人)。


感谢您的输入,谢谢!不过,您的第二个组并不是我正在寻找的。我希望将affilaup作为单独的组,而不是在同一个组中... - coolDude
3
如果 OP 在分号上拆分,那么“name”标记将与前面的部分合并。大型模式中没有分号分隔。 - Ian McLaird
@IanMcLaird:没错,Ian。 - Jan
@coolDude:更新了答案,现在整数和浮点数是分开的。 - Jan
@Jan,非常接近了!不过我需要知道哪些整数或浮点数与“affil”相关,哪些整数与“aup”相关。 - coolDude
显示剩余3条评论

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();
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接