【问题标题】:Generate new word from wildcard [duplicate]从通配符生成新词[重复]
【发布时间】:2015-07-02 03:59:26
【问题描述】:

我正在尝试使用通配符生成一个单词并检查该单词是否存储在字典数据库中。像“appl*”应该返回apply或apple。但是,当我有 2 张通配符时,问题就来了。 "app**" 将生成 appaa、appbb..appzz... 之类的词,而不是 apple。第二个 if 条件仅适用于不包含通配符的常规字符串“*”

 public static boolean printWords(String s) {
    String tempString, tempChar;
    if (s.contains("*")) {

        for (char c = 'a'; c <= 'z'; c++) {

            tempChar = Character.toString(c);
            tempString = s.replace("*", tempChar);

            if (myDictionary.containsKey(tempString) == true) {
                System.out.println(tempString);
            } 
        } 
    }
    if (myDictionary.containsKey(s) == true) {
        System.out.println(s);
        return true;
    } else {
        return false;
    }
}

【问题讨论】:

标签: java wildcard


【解决方案1】:

您只对字符使用单个 for 循环,并将 * 的 all 实例替换为该字符。 See the API for String.replace here。因此,您得到 Appaa、Appbb 等字符串也就不足为奇了。

如果您想实际使用 Regex 表达式,那么您不应该执行任何 String.replace 或 contains 等操作。请参阅 Anubian 的答案以了解如何处理您的问题。

如果您将此视为字符串练习并且不想使用正则表达式,那么执行您实际尝试执行的操作(尝试每个通配符的所有字母组合)的最简单方法就是执行此操作递归地。如果字符串中没有通配符,检查它是否是一个单词,如果是则打印。如果有通配符,请尝试用一个字符替换该通配符,并递归调用创建的字符串上的函数。

public static void printWords(String s){
    int firstAsterisk = s.indexOf("*");
    if(firstAsterisk == -1){ // doesn't contain asterisk
        if (myDictionary.containsKey(s))
            System.out.println(s);
        return;
    }

    for(char c = 'a', c <= 'z', c++){
        String s2 = s.subString(0, firstAsterisk) + c + s.subString(firstAsterisk + 1);
        printWords(s2);
    }
}

基本原因依赖于the indexOf function - 当 indexOf 返回 -1 时,这意味着字符串中没有出现给定的子字符串(在我们的例子中是“*”) - 因此没有更多的通配符可以替换。

子字符串部分基本上是重新创建原始字符串,其中第一个星号替换为字符。所以假设s = "abcd**ef"c='z',我们知道firstAsterisk = 4(字符串是0索引的,索引4有第一个“*”)。因此,

String s2 = s.subString(0, firstAsterisk) + c + s.subString(firstAsterisk + 1);
          = "abcd" + 'z' + "*ef"
          = "abcdz*ef"

【讨论】:

  • +1 好答案!如果您解释一下您的代码是如何工作的,那将是一个更好的答案。尤其是递归部分,并不是每个人都直观。
  • 谢谢。我理解递归部分。我对子字符串部分有点困惑。你能解释一下基本情况-1部分吗?
  • 没问题!更新了我的答案
【解决方案2】:

* 字符是正则表达式通配符,因此您可以将输入字符串视为正则表达式:

for (String word : myDictionary) {
    if (word.matches(s)) {
        System.out.println(word);
    }
}

让图书馆为您完成繁重的工作;)

【讨论】:

  • 所以我必须遍历整个单词列表?有没有办法不必这样做?
  • 是的...我不这么认为,所以我想这更慢...?取决于单词的大小和字典的大小,但可能会更慢。
【解决方案3】:

使用您的方法,您必须检查所有可能的组合。 更好的方法是从您的输入字符串中创建一个正则表达式,因此将所有* 替换为.

然后您可以遍历您的 myDirectory 并检查每个条目是否与正则表达式匹配。

类似这样的:

Set<String> dict = new HashSet<String>();
dict.add("apple");

String word = "app**";
Pattern pattern = Pattern.compile(word.replace('*', '.'));

for (String entry : dict) {
  if (pattern.matcher(entry).matches()) {
    System.out.println("matches: " + entry);
  }
}

如果您的输入字符串已经包含.,您必须小心,而不是使用\ 转义它们。 (对于其他特殊的正则表达式字符也是如此。)

另请参阅 http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.htmlhttp://docs.oracle.com/javase/6/docs/api/java/util/regex/Matcher.html

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-08-09
    • 1970-01-01
    • 1970-01-01
    • 2011-07-01
    • 2019-03-05
    • 1970-01-01
    • 1970-01-01
    • 2021-12-18
    相关资源
    最近更新 更多