检查子串是否在忽略大写、小写和特殊字符的字符串中?

Check If a substring is in a string ignoring uppercase, lowercase and special characters?

我正在尝试检查 "Homemade Pizza!" 之类的短语是否包含 "pizza" 之类的字符串,但我希望它始终为真,是否无关紧要这是披萨或披萨或披萨!或披萨!

我来解释一下代码:

recipesFounded 是一个包含标题、描述等的数组。这就是为什么我把 recipesFounded.get(i).getTitle().

问题是我有 "Homemade Pizza!" 字符串,所以如果我搜索 "Pizza!" 很好,因为食谱已添加到 trueOnes 新食谱列表中,但如果我搜索披萨(没有 mayus P 和!)它没有。

这个词是我要搜索的字符串(pizza, Pizza!...)


for (int i=0; i < recipesFounded.size(); i++) {
    if (recipesFounded.get(i).getTitle().contains(word)) {
       trueOnes.add(recipesFounded.get(i));
    }
}

使用String

toLowerCase方法

word = word.replaceAll("[^a-zA-Z]","").toLowerCase(); // keep only letters

根据 Andreas 的建议,在循环之前将单词转换为小写。效率更高。

for (int i=0; i < recipesFounded.size(); i++) {
    if (recipesFounded.get(i).getTitle().toLowerCase()
              .contains(word)) {
       trueOnes.add(recipesFounded.get(i));
    }
}

由于List实现了iterable接口,你可以这样操作。它假定您正在使用一个名为 Recipe

的 class
for (Recipe recipe : recipesFounded) {
    if (recipe.getTitle().toLowerCase()
            .contains(word)) {
       trueOnes.add(recipe);
    }
}

为了按给定顺序搜索 letters/digits,忽略大小写、空格和特殊字符,最好将搜索字符串转换为 常规表达式.

要允许搜索字符串 "foobar""Foo-Bar" 匹配,我们需要在任何字母数字字符之间允许特殊字符。

为了完全支持 Unicode,我们将使用 \p{Alnum} and flags UNICODE_CHARACTER_CLASS, CASE_INSENSITIVE, and UNICODE_CASE,或者更确切地说,大写 P 表示非字母数字。

匹配例如AÁ,我们还 分解 Unicode 字符,使用 Normalizer.normalize(str, Normalizer.Form.NFD).

这是一个如何做到这一点的例子:

static List<String> search(List<String> texts, String word) {
    String regex = Normalizer.normalize(word, Normalizer.Form.NFD) // e.g. "Á"  ->  "A\u0301"
            .replaceAll("(?U)\P{Alnum}+", "")                     // e.g. "I'm!"  ->  "Im"
            .replaceAll("(?<=.)(?=.)", "\\P{Alnum}*"); // insert '\P{Alnum}*' between all characters 
    Pattern p = Pattern.compile(regex, Pattern.UNICODE_CHARACTER_CLASS |
                                       Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
    List<String> trueOnes = new ArrayList<>();
    for (String text : texts) {
        if (p.matcher(Normalizer.normalize(text, Normalizer.Form.NFD)).find()) {
            trueOnes.add(text);
        }
    }
    return trueOnes;
}

测试

List<String> texts = List.of("Homemade Pizza!", "Dessert", "Pizza Hut", "Potato-Söûp", "O'Malleys Ale");
System.out.println(search(texts, "pizza"));    // [Homemade Pizza!, Pizza Hut]
System.out.println(search(texts, "made, pi")); // [Homemade Pizza!]
System.out.println(search(texts, "ömÁl"));     // [O'Malleys Ale]
System.out.println(search(texts, "TOSO"));     // [Potato-Söûp]