负向先行断言 Java

4

我需要一个表达式来捕获类似于以下的字符串:

"A"[不少于5位且不多于6位数字的字符串]"B",换句话说,捕获任何不符合以下规则的内容:

A[0-9][0-9][0-9][0-9][0-9]B
A[0-9][0-9][0-9][0-9][0-9][0-9]B

我尝试过使用负向先行断言:

regex = "a((?![0-9]{5,6}).)*d";

但它无法捕获所有情况。


1
你的例子中的 ad 是什么?难道你不是想匹配 AB 吗? - erickson
4个回答

6
A(?!\d{5,6}B).*B

你只需要在A之后进行一次前瞻。同时,你需要将B包含在前瞻中,这样它就不会拒绝任何包含超过六位数字的内容。

+1。对于那些说这不可读的人,请花时间学习如何阅读它。 - polygenelubricants

4

这只是几行非常简单、易懂、可靠的代码,你可以在发布并获得RE版本响应的时间内写并重写3次。当然,使用RE版本时,你所做的事情并不明显。

int examine(String s) {
    int foundAt=-1;

    for(int i=0;i<s.length;i++) {
        char c=s.charAt(i); // something like that
        if(c=='A') { 
            foundAt=i;               
            continue;
        }

        if(foundAt != -1) {
            if(c == 'B' && i-foundAt < 5 || i-foundAt > 6)
                return foundAt;  

            if(!String.isNumber(c)) // something like that
                foundAt = -1;  // Not a number before B, reset
        }
    }
    return -1;
}

好的,所以虽然这不仅仅是几行代码(但它也被包含在一个函数调用中),但修改其行为来做一些棘手的事情比修改正则表达式更加直接,因为对RE的更改很容易造成意外后果,应该很容易阅读,一旦消除了前几个简单的错误,它将是完美无缺的——这似乎从来不适用于正则表达式。

那么,这难道不是你能够得到的最短和最易读的代码吗?

n=examine(s);

任何缩短代码的“优势”,如果用易于阅读、可靠的函数调用替换,则完全消除。 (我猜这很可能是一道作业问题,如果是的话,这个答案不应该正确回答它)

1
这是一个糟糕的想法,不会更清晰、更明显或更容易修改。正如其他回答者所示,修改是微不足道的。对于模式匹配,正则表达式是正确的工具,如果某个特定情况不清楚,两行文档(例如匹配、排除示例)比二十行误导更好。 - Joe Atzberger

3
你差不多就做到了。试试这个方法:
"A(?![0-9]{5,6}B).*B"

请注意,".*"将贪婪地匹配;如果有多个B的出现,则匹配将以最后一个结束,而不是第一个。你可能想使用".*?"代替。例如,如果你有一个长字符串,其中有多个此模式的出现,并且你正在使用find()方法扫描输入字符串,那么你需要进行勉强匹配。

1

这是一道作业题吗?

我不确定你的正则表达式中为什么有 "a" 和 "d"。

这个正则表达式可以处理从 0 到 4 位数字和 7 位或更多位数字。

String rexexp = "A(\\d{0,4}|\\d{7,})B";

1
你假设在 AB 之间只能有数字。但我理解的是,那里面可以是任何东西,只是问题不是很清楚。 - Alan Moore

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