0

这些是我不应该在我的地址中允许的字符串:

"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]*))";
4

3 回答 3

2

我猜您正在尝试查看地址字符串是否包含任何受限短语。

请不要在一个正则表达式中执行此操作。

执行一个单一的大规模正则表达式匹配查询意味着很难理解您为创建正则表达式所做的工作,如果出现更多限制则难以扩展,并且通常不是良好的代码实践。


这是一个(希望)更理智的方法:

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 注入它,这样您讨厌的产品人员就可以添加地址限制而无需接触 une ligne de 代码。


编辑:为了使这更容易阅读,并做你真正想要的(限制使用空格与其他字符串分隔的字符串),你可以从限制中完全删除正则表达式,并在你的方法中做一些基本的匹配工作。

// 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;
}
于 2013-09-11T18:33:18.810 回答
1

那么,您想像专业人士一样搜索子字符串吗?我建议使用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则为真。

注意:此搜索区分大小写。由于您的字符串都是大写的,我建议您首先将地址转换为临时大写变体并对其使用匹配。这样,您将涵盖所有可能的组合。

根据我的测试,Aho Corasick 比基于正则表达式的搜索更快,并且在大多数情况下比使用简单字符串搜索contains和其他基于字符串的方法更快。您可以添加更多过滤词;Aho Corasick 是要走的路。

于 2013-09-12T08:51:09.287 回答
0

而不是使用如此复杂的正则表达式,您可以声明:正则表达式:

"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"

并否定答案。

当您编译正则表达式(in Java)时,生成的机制将变得更加高效。(Java 使用 DFA 最小化)。

于 2013-09-11T18:24:41.160 回答