簡體   English   中英

如何通過添加更多字符來了解字符串是否可以匹配正則表達式

[英]How to know if a string could match a regular expression by adding more characters

這是一個棘手的問題,也許最終它沒有解決方案(至少沒有合理的解決方案)。 我想要一個特定於Java的示例,但是如果可以做到,我想我可以通過任何示例來做到。

我的目標是找到一種方法來了解從輸入流中讀取的字符串是否仍可以匹配給定的正則表達式模式。 或者,換句話說,讀取流,直到我們得到一個絕對不匹配這種模式的字符串,無論您添加了多少字符。

為實現這一目的而使用的簡單方法的聲明可能類似於:

boolean couldMatch(CharSequence charsSoFar, Pattern pattern);

如果添加新字符后charsSoFar仍然可以匹配pattern,則該方法將返回true ;否則,即使添加新字符也沒有機會匹配它,否則將返回false

舉一個更具體的例子,假設我們有一個浮點數模式,例如"^([+-]?\\\\d*\\\\.?\\\\d*)$"

通過這種模式,對於以下示例charsSoFar參數, couldMatch將返回true

"+"  
"-"  
"123"  
".24"  
"-1.04" 

依此類推,等等,因為您可以繼續在所有這些數字中加上數字,並且在前三個數字中也加上一個點。

另一方面,從上一個示例派生的所有這些示例都應返回false

"+A"  
"-B"  
"123z"  
".24."  
"-1.04+" 

乍一看很明顯,無論您添加多少個字符,這些字符都永遠不會符合上述模式。

編輯:

我現在添加我當前的非正則表達式方法,以便使事情更加清楚。

首先,我聲明以下功能接口:

public interface Matcher {
    /**
     * It will return the matching part of "source" if any.
     *
     * @param source
     * @return
     */
    CharSequence match(CharSequence source);
}

然后,將先前的函數重新定義為:

boolean couldMatch(CharSequence charsSoFar, Matcher matcher);

浮點數(草稿)匹配器可能看起來像(請注意,開頭不支持+號,僅支持-):

public class FloatMatcher implements Matcher {
    @Override
    public CharSequence match(CharSequence source) {
        StringBuilder rtn = new StringBuilder();

        if (source.length() == 0)
            return "";

        if ("0123456789-.".indexOf(source.charAt(0)) != -1 ) {
            rtn.append(source.charAt(0));
        }

        boolean gotDot = false;
        for (int i = 1; i < source.length(); i++) {
            if (gotDot) {
                if ("0123456789".indexOf(source.charAt(i)) != -1) {
                    rtn.append(source.charAt(i));
                } else
                    return rtn.toString();
            } else if (".0123456789".indexOf(source.charAt(i)) != -1) {
                rtn.append(source.charAt(i));
                if (source.charAt(i) == '.')
                    gotDot = true;
            } else {
                return rtn.toString();
            }
        }
        return rtn.toString();
    }
}

在mayMatch方法的省略的正文中,它將僅迭代調用matcher.match(),並在源參數的末尾添加一個新字符,並在返回的CharSequence等於源參數的同時返回true,並在返回時立即返回false。這是不同的(意味着最后添加的字符破壞了比賽)。

您可以輕松完成

boolean couldMatch(CharSequence charsSoFar, Pattern pattern) {
    Matcher m = pattern.matcher(charsSoFar);
    return m.matches() || m.hitEnd();
}

如果序列不匹配,並且引擎未到達輸入的末尾,則表示末尾有一個矛盾的字符,當在末尾添加更多字符時,該字符不會消失。

或者,如文檔所述

如果在此匹配器執行的最后一個匹配操作中搜索引擎命中輸入的末尾,則返回true。

當此方法返回true時,則可能有更多輸入會更改上一次搜索的結果。

Scanner類在內部也使用此方法,以確定是否應從源流中加載更多數據以進行匹配操作。

將上述方法與樣本數據一起使用

Pattern fpNumber = Pattern.compile("[+-]?\\d*\\.?\\d*");
String[] positive = {"+", "-", "123", ".24", "-1.04" };
String[] negative = { "+A", "-B", "123z", ".24.", "-1.04+" };
for(String p: positive) {
    System.out.println("should accept more input: "+p
                      +", couldMatch: "+couldMatch(p, fpNumber));
}
for(String n: negative) {
    System.out.println("can never match at all: "+n
                      +", couldMatch: "+couldMatch(n, fpNumber));
}
should accept more input: +, couldMatch: true
should accept more input: -, couldMatch: true
should accept more input: 123, couldMatch: true
should accept more input: .24, couldMatch: true
should accept more input: -1.04, couldMatch: true
can never match at all: +A, couldMatch: false
can never match at all: -B, couldMatch: false
can never match at all: 123z, couldMatch: false
can never match at all: .24., couldMatch: false
can never match at all: -1.04+, couldMatch: false

當然,這並沒有說明將不匹配內容轉換為匹配內容的可能性。 您仍然可以構造任何其他字符都無法匹配的模式。 但是,對於像浮點數格式這樣的普通用例,這是合理的。

我沒有具體的解決方案,但是您可以通過否定來做到這一點。

如果您在黑名單中設置的正則表達式模式絕對與您的模式不匹配(例如+后跟char),則可以進行檢查。 如果列入黑名單的正則表達式返回true,則可以中止。

另一個想法是使用否定先行( https://www.regular-expressions.info/lookaround.html

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM