正则表达式匹配字符串
- 简介
- 具体方案
- 生成正则表达式的代码实现
简介
需求内容:需要将不同的公司名称归一化
比如namecheap, NAMECHEAP. INC. 等表示同一含义,但是表现形式不同
本文使用java语言实现了由一串字符串自动生成精确匹配的正则表达式的方式,并顺带介绍了归一化不同表达方式的公司为同一个公司的方案
具体方案
将收集到的域名注册商或者服务提供商进行字典序的排序,然后按照字母字典序来拆分成(26个字母+其他语言)的集合,每个集合分开来处理每个字母对应的注册商和服务商,将复杂问题拆解,划分成更小的问题进行解决
1、找出同一个字母开头的服务商或者注册商群进行归类
- 截取掉一些关键信息,包括以下的几类缩写:
- 有限公司
- Ltd.(Limited):常见于英语国家,如美国、英国、加拿大、澳大利亚等。
- S.A.(Societe Anonyme):常见于法语国家,如法国、瑞士、比利时、卢森堡、意大利、西班牙、葡萄牙等。
- GmbH(Gesellschaft mit beschränkter Haftung):常见于德语国家,如德国、瑞士等。
- K.K.(Kabushiki Kaisha):常见于日语国家,如日本、韩国等。
- S.R.L.(Società a responsabilità limitata):常见于意大利语国家,如意大利、墨西哥等。
- S.A.R.L.(Société à responsabilité limitée):常见于法语国家,如法国、比利时、卢森堡等。
- B.V.(Besloten Vennootschap):常见于荷兰语国家,如荷兰、比利时、卢森堡等。
- N.V.(Naamloze Vennootschap):常见于荷兰语国家,如荷兰、比利时、卢森堡等。
- 股份有限公司
- Plc.(Public Limited Company):常见于英语国家,如英国、加拿大、澳大利亚等。
- S.A.(Societe Anonyme):常见于法语国家,如法国、瑞士、比利时、卢森堡、意大利、西班牙、葡萄牙等。
- AG(Aktiengesellschaft):常见于德语国家,如德国、瑞士等。
- K.K.(Kabushiki Kaisha):常见于日语国家,如日本、韩国等。
- S.A.P.A.(Società per Azioni):常见于意大利语国家,如意大利、墨西哥等。
- S.A.R.L.(Société Anonyme à Responsabilité Limitée):常见于法语国家,如法国、比利时、卢森堡等。
- B.V.A.(Besloten Vennootschap met Aandeelhouders):常见于荷兰语国家,如荷兰、比利时、卢森堡等。
- INC.(Incorporated) 代表股份邮箱公司
- 其他
- Co. (Company):常见于英语国家,表示公司。
- Ltd. Co.(Limited Company):常见于英语国家,表示有限公司。
- Pte. Ltd.(Private Limited Company):常见于新加坡,表示私人有限公司。
- S.C.(Società Civile):常见于意大利语国家,表示合伙公司。
- S.C.S.(Società in accomandita semplice):常见于意大利语国家,表示有限合伙公司。
- S.N.C.(Società in nome collettivo):常见于意大利语国家,表示无限合伙公司。
- S.L.(Sociedad Limitada):西班牙语有限责任公司
- Inc.(incorporated )股份有限公司的常见缩写
- Limited (limited liability company)有限责任公司的缩写
- LLC(limited liability company)有限责任公司的缩写
- Co.,(company)公司的缩写,类似还有Corp.Co.
对于每个公司名称,先根据这些常见的缩写进行拆分:
拆分完成之后,在每个字母开头的集群里去进行正则匹配,不区分大小,如何匹配到相同的正则表达式(由开发定义),匹配成功,则合成一个并查集
对于一些没办法通过自动正则表达式规则匹配的,通过手动配置相关联的名称为同一个正则表达式,然后将两个集合合并在一起。
生成正则表达式的代码实现
// 生成归一化的正则表达式public static String generateRegularExpression(String str,Map<Integer, List<String>> companySuffixMap, List<String> pureCompanySuffix) {String strToLowerCase = str.toLowerCase();//先遍历特殊的公司后缀for(Integer innerElement : companySuffixMap.keySet()) {List<String> companySuffixList = companySuffixMap.get(innerElement);for(String companySuffix : companySuffixList) {String companySuffixToLowerCase = companySuffix.toLowerCase(Locale.ROOT);int index = strToLowerCase.indexOf(companySuffixToLowerCase);if(index != -1) {String prefixStr = strToLowerCase.substring(0, index);return "^(?i)" + matchRegx(prefixStr) + ".*$";}}}//再遍历英文公司后缀for(String englishCompanySuffix : pureCompanySuffix) {String companySuffixToLowerCase = englishCompanySuffix.toLowerCase(Locale.ROOT);int index = strToLowerCase.indexOf(companySuffixToLowerCase);if(index != -1) {if(index == 0) {continue;}if(strToLowerCase.charAt(index - 1) == ' ' || strToLowerCase.charAt(index - 1) == ','|| strToLowerCase.charAt(index - 1) == '.') {String prefixStr = strToLowerCase.substring(0, index-1);return "^(?i)" + matchRegx(prefixStr) + ".*$";}}}//实在不行,就进行全匹配return "^(?i)" + matchRegx(str) + "$";}public static String matchRegx(String prefixStr) {return escapeSpecialCharacters(prefixStr).replaceAll("[ ,.]", "[\\\\s|,|\\.]*");}public static String escapeSpecialCharacters(String inputString) {StringBuilder escapedString = new StringBuilder();for (char character : inputString.toCharArray()) {switch (character) {case '\\':escapedString.append("\\\\");break;case '*':escapedString.append("\\*");break;case '+':escapedString.append("\\+");break;case '?':escapedString.append("\\?");break;case '[':escapedString.append("\\\\[");break;case ']':escapedString.append("\\\\]");break;case '(':escapedString.append("\\(");break;case ')':escapedString.append("\\)");break;case '{':escapedString.append("\\{");break;case '}':escapedString.append("\\}");break;case '^':escapedString.append("\\^");break;case '$':escapedString.append("\\$");break;case '|':escapedString.append("\\|");break;case '-':escapedString.append("\\-");break;case '/':escapedString.append("\\/");break;default:escapedString.append(character);}}return escapedString.toString();}