如何使用正则表达式与Predicate过滤Stream流以获取不符合规则的城市名列表
解决城市名非法字符筛选问题
看起来你在筛选含非法字符的城市名时,因为正则表达式的逻辑偏差,导致结果和预期完全相反。咱们来拆解问题并修复它:
问题根源:当前正则的逻辑错误
你现在用的正则[^a-z0-9-]*$,意思是字符串结尾有0个或多个非法字符。但*允许匹配0次,这意味着所有完全合法的城市名(没有任何非法字符)也会被这个规则匹配到,所以filter会把所有城市都放进invalidCharactersList,这就是为什么第一个全合法的列表也触发了异常。
两种正确的实现方案
方案1:直接匹配含非法字符的城市名
我们需要一个能匹配至少包含一个非法字符的正则,正确写法是.*[^a-z0-9-].*,它的逻辑是:
.*:匹配任意数量的任意字符(开头部分)[^a-z0-9-]:精准匹配一个不在允许范围内的字符(核心的非法检测).*:匹配任意数量的任意字符(结尾部分)
修改后的代码:
String str; List<String> invalidCharactersList = cityName.stream() .filter(Pattern.compile(".*[^a-z0-9-].*").asPredicate()) .collect(Collectors.toList()); // 检查非法名称 if (!invalidCharactersList.isEmpty()) { str = (inOut) ? "c" : "q"; throw new IllegalArgumentException("City name characters " + str + ": for city name " + invalidCharactersList.get(0) + ": fails constraint city names [a-z, 0-9, -]"); }
方案2:先匹配合法城市名,再取反
另一种更直观的思路:先定义“合法城市名”的规则,再筛选出不满足这个规则的城市。合法城市名的正则是^[a-z0-9-]+$,含义是:
^:字符串开头[a-z0-9-]+:匹配至少一个允许的字符(a-z、0-9、-)$:字符串结尾
然后用negate()把规则取反,就得到了非法城市名的筛选条件:
String str; List<String> invalidCharactersList = cityName.stream() .filter(Pattern.compile("^[a-z0-9-]+$").asPredicate().negate()) .collect(Collectors.toList()); // 检查非法名称 if (!invalidCharactersList.isEmpty()) { str = (inOut) ? "c" : "q"; throw new IllegalArgumentException("City name characters " + str + ": for city name " + invalidCharactersList.get(0) + ": fails constraint city names [a-z, 0-9, -]"); }
测试验证
用你提供的测试列表q = Arrays.asList("fastcity*", "bigbanana", "xyz&"),两种方案都会把"fastcity*"和"xyz&"筛选进invalidCharactersList,触发异常,完全符合你的预期;而全合法的列表c会让invalidCharactersList为空,不会抛出异常。
内容的提问来源于stack exchange,提问作者charlie f
相关产品推荐
相关产品推荐

