簡體   English   中英

如何使用正則表達式檢查字符串是否包含受限詞?

[英]How do I check if a String contains restricted words using Regex?

這些是我不應在我的地址中使用的字符串:

"PO BOX","P0 DRAWER","POSTOFFICE", " PO ", " BOX ",
 "C/O","C.O."," ICO "," C/O "," C\0 ","C/0","P O BOX",
 "P 0 BOX","P 0 B0X","P0 B0X","P0 BOX","P0BOX","P0B0X",
 "POBX","P0BX","POBOX","P.0.","P.O","P O "," P 0 ",
 "P.O.BOX","P.O.B","POB ","P0B","P 0 B","P O B",
 " CARE ","IN CARE"," APO "," CPO "," UPO ", "GENDEL",
 "GEN DEL", "GENDELIVERY","GEN DELIVERY","GENERALDEL",
 "GENERAL DEL","GENERALDELIVERY","GENERAL DELIVERY"

我創建了正則表達式:此表達式僅驗證POBOx部分–請更正,不允許在我的地址字段中使用上述所有字符串

"([\\w\\s*\\W]*((P(O|OST)?.?\\s*((O(FF(ICE)?)?)?.?\\s*(B(IN|OX|.?))|B(IN|OX))+))[\\w\\s*\\W]*)+
|([\\w\\s*\\W]* (IN \s*(CARE)?\\s*)|\s*[\\w\\s*\\W]*((.?(APO)?|.?(cPO)?|.?(uPO))?.?\s*) [\\w\\s*\\W]*|([\\w\\s*\\W]*(GEN(ERAL)?)?.?\s*(DEL(IVERY)?)?.?\s* [\\w\\s*\\W]*))";

我猜您正在嘗試查看地址字符串是否包含任何受限短語。

請不要在一個正則表達式中執行此操作。

進行單個大規模正則表達式匹配查詢意味着很難理解創建正則表達式的操作,如果彈出更多限制則很難擴展,並且通常也不是良好的代碼習慣。


這是(希望)更加理智的方法:

public static final String RESTRICTIONS[] = { " P[0O] ", " B[0O]X ", "etc, etc" };

public static boolean containsRestrictions(String testString) {
    for (String expression : RESTRICTIONS) {
        Matcher restriction = Pattern.compile(expression).matcher(testString);
        if (restriction.find())
            return true;
    }
    return false;
}

您仍在進行正則表達式匹配,因此可以將您喜歡的schmancy正則表達式放入您的限制列表中,但它也僅適用於普通的舊字符串。 現在,您只需要驗證每個正則表達式是否正常工作,而不用針對所有可能的情況驗證巨型正則表達式。 如果您想添加新的限制,只需將其添加到列表中即可。 如果您真的很喜歡,您可以從配置文件中加載限制,也可以使用spring注入限制,以便您討厭的產品人員可以添加地址限制,而無需觸摸任何代碼。


編輯:為了使它更易於閱讀,並真正想要做(使用空格限制將字符串與其他字符串分隔開),可以從限制中完全刪除正則表達式,並在方法中執行一些基本的匹配工作。

// No regexes here, just words you wanna restrict
public static final String RESTRICTIONS[] = { "PO", "PO BOX", "etc, etc" };

public static boolean containsRestrictions(String testString) {
    for (String word : RESTRICTIONS) {
        String expression = "(^|\\s)" + word + "(\\s|$)";
        Matcher restriction = Pattern.compile(expression).matcher(testString);
        if (restriction.find())
            return true;
    }
    return false;
}

因此,您想像專業人士一樣搜索子字符串嗎? 我建議使用Aho Corasick算法來解決您遇到的問題。

賣點:

它是一種字典匹配算法,用於在輸入文本中定位字符串的有限集合(“字典”)的元素。 它同時匹配所有模式。

幸運的是,存在Java實現。 你可以在這里得到。

使用方法如下:

// this is the part you have to do only once

AhoCorasick tree = new AhoCorasick(); 

String[] terms = {"PO BOX","P0 DRAWER",...};

for (int i = 0; i < terms.length; i++) {
     tree.add(terms[i].getBytes(), terms[i]); 
}
tree.prepare();



// here comes the part you use for every address you want to check

String text = "The ga3 mutant of Arabidopsis is a gibberellin-responsive. In UPO, that is...";

boolean restrictedWordFound = false;

@SuppressWarnings("unchecked")
Iterator<SearchResult> search = (Iterator<SearchResult>)tree.search(text.getBytes());

if(search.hasNext()) {
    restrictedWordFound = true;
}

如果找到匹配項,則restrictedWordFound將為true。

注意:此搜索區分大小寫。 由於您的字符串全部為大寫,因此建議您首先將地址轉換為臨時的大寫變體,然后對其進行匹配。 這樣,您將涵蓋所有可能的組合。

根據我的測試,Aho Corasick比基於正則表達式的搜索要快,並且在大多數情況下比使用contains和其他基於String的方法的朴素字符串搜索要快。 您可以添加更多過濾詞; Aho Corasick是必經之路。

您可以聲明:regex而不是使用這種復雜的正則表達式:

"PO BOX|P0 DRAWER|POSTOFFICE| PO | BOX |C/O|C.O.| ICO | C/O | C\0 |C/0|P O BOX|P 0 BOX|P 0 B0X|P0 B0X|P0 BOX|P0BOX|P0B0X|POBX|P0BX|POBOX|P.0.|P.O|P O | P 0 |P.O.BOX|P.O.B|POB |P0B|P 0 B|P O B| CARE |IN CARE| APO | CPO | UPO |GENDEL|GEN DEL|GENDELIVERY|GEN DELIVERY|GENERALDEL|GENERAL DEL|GENERALDELIVERY|GENERAL DELIVERY"

並否定答案。

當您編譯正則表達式(使用Java )時,生成的機制將變得更加高效。 (Java使用DFA最小化)。

暫無
暫無

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

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