我的情况是我有一个包含8个字符长字符串的列表,其中包含通配符(由?
表示),我需要匹配一个也带有通配符的输入字符串。所述字符串由四个字母字符(A-Z)和四个数字(0-9)组成。为了便于理解,这是一组字符串的示例:
ABCD1234
A??D123?
A???????
?BC1234?
如果我将A?CD12?4
作为输入,则比较应在每次比较中解析为true。
我当前的实现是使用Hashmap,使用字符串作为键,并将与regex相同的字符串解析为对象映射。例如,A?CD12?4
变为A([A-Z]|\\?)CD12([0-9]|\\?)4
,然后使用以下代码获取一组兼容字符串:
Map<String, String> map = new HashMap<String, String>();
map.put("A???????", "A([A-Z]|\\?)([A-Z]|\\?)([A-Z]|\\?)([0-9]|\\?)([0-9]|\\?)([0-9]|\\?)([0-9]|\\?)");
map.put("ABCD1234", "ABCD1234");
map.put("A??D123?", "A([A-Z]|\\?)([A-Z]|\\?)D123([0-9]|\\?)");
map.put("?BCD123?", "([A-Z]|\\?)BC123([0-9]|\\?)");
String str = "A?CD12?4";
String strReg = "A([A-Z]|\\?)CD12([0-9]|\\?)4";
Set<Object> set = map.keySet()
.stream()
.filter(s -> str.matches(map.get(s)) || s.matches(strReg) )
.collect(Collectors.toSet());
然而,这仍然错过了输入,其中str
中的通配符问号但未显示在地图字符串上(例如,输入A?CD1234
无法解析为?BCD1234
和-versa)。
虽然我知道通过遍历String来解决这个问题很简单,但我的解决方案需要将输入与 50000 字符串进行比较,并且我以大于的速率读取输入30 /秒,所以表现很关键。
此处理在Thread内部进行,外部交互可以更改输入将检查的字符串列表(仅添加或删除)。
答案 0 :(得分:2)
作为一般规则,比较字符串时可以忽略?
通配符。由于这可以用于所有模式,因此不需要在地图中存储正则表达式替代,可以在迭代时推断可以跳过该字符。这是使用并行流的更快的解决方案:
Set<String> patterns = new HashSet<>();
patterns.add("A???????");
patterns.add("ABCD1234");
patterns.add("A??D123?");
patterns.add("?BCD123?");
String s = "A?CD12?4";
Set<String> matches = patterns.parallelStream() // the main benefit of this
.filter(p -> {
for (int i = 0; i < s.length(); i++) {
char a = s.charAt(i),
b = p.charAt(i);
if (a != '?' && b != '?' && a != b)
return false;
}
return true;
}).collect(Collectors.toSet());
答案 1 :(得分:1)
我不会使用正则表达式。只需直接比较两个字符串的字符:
boolean formatCorrect(String a) {
if (a.length() != 8) return false;
for (int i = 0; i < 4; ++i) {
char ca = a.charAt(i);
if (ca != '?' && !Character.isLetter(ca)) {
return false;
}
}
for (int i = 4; i < 8; ++i) {
char ca = a.charAt(i);
if (ca != '?' && !Character.isDigit(ca)) {
return false;
}
}
return true;
}
boolean stringsMatch(String a, String b) {
if (!formatCorrect(a) || !formatCorrect(b)) {
// Handle this. Maybe an IllegalArgumentException?
}
for (int i = 0; i < 8; ++i) {
char ca = a.charAt(i);
char cb = b.charAt(i);
if (ca != '?' && cb != '?' && ca != cb) return false;
}
return true;
}
这将非常快,因为它没有分配任何对象。
您可以通过将一些检查移出循环来优化它(例如,检查字符串a
和b
的格式是正确的格式。)