基本上,您使用通配符遍历字符串(从现在开始我将调用该字符串 pattern):
如果模式的第一个字符不是?,则尝试从输入字符串(另一个没有通配符的字符串)中准确使用该字符。
如果模式的第一个字符是?,那么你有两种情况:
-
? 应该匹配一个字符(为了匹配完整的模式),所以只需使用输入中的下一个字符并继续。
-
? 不应匹配字符,在这种情况下,您将继续使用模式中的下一个字符并保持输入字符串不变。
当然,您之前无法知道何时选择这些案例中的哪一个。所以你需要能够回到那个点,以防你的猜测是错误的。
为此,您可以使用递归(或更准确地说:就局部变量等而言,您从递归调用中获得的新上下文):
您只需首先使用剩余的模式和输入字符串调用匹配函数,如果失败,您使用剩余的模式和输入字符串调用匹配函数没有它的第一个字符(从而使? 消耗一个字符)。
例子:
pattern: s?y
input: say
模式的第一个字符是s,这是正常的非通配符匹配,所以查看匹配的输入的第一个字符,继续前进:
pattern: ?y
input: ay
现在有一个通配符要匹配,所以假装它没有消耗任何字符,让我们看看它会把我们带到哪里。调用匹配函数:
pattern: y
input: ay
哎呀,这不匹配(a != y),所以此时返回false。这让我们回到了我们调用匹配函数的地方(在上面的步骤中),给我们留下了:
pattern: ?y
input: ay
我们已经尝试将通配符匹配为无字符,现在尝试将其匹配为任何字符,从而消耗a:
pattern: y
input: y
哇,匹配,下一次运行时两个字符串都是空的,所以我们有一个匹配!
这似乎是家庭作业,您可能必须在 C++ 中实现。我不会给你那个代码。相反,我会给你一个不同语言的实现——Clojure——它应该能让你进一步理解上述算法。
(ns wildcards
(:refer-clojure))
(defn- dpr
"Debug printing with poor man's indendation"
[pattern & rest]
(print (repeat (- 6 (count pattern)) " "))
(apply println rest))
(defn wildcard-match [input pattern]
(println "wildcard-match " input pattern)
(if (or (empty? input) (empty? pattern))
;; One is empty, return true if both are
(and (empty? input) (empty? pattern))
;; Else
(if (= (first pattern) \?)
;; Wildcard, so with short ciruiting or:
(or (do
(dpr pattern "Try to match no character...")
(wildcard-match input (rest pattern)))
(do
(dpr pattern "Ok, so try to match any character...")
(recur (rest input) (rest pattern))))
;; Non-Wildcard, test for equality, and if equal, go on.
(and (= (first pattern) (first input))
(recur (rest input) (rest pattern))))))
(defn testcase [input pattern]
(println "#####################################")
(println "Trying to match" input "with" pattern)
(println "=>" (wildcard-match (seq input) (seq pattern)))
(println))
(doall (map #(testcase (first %) (second %))
[["hello" "hello"]
["hello" "h?l?o"]
["hllo" "h?l?o"]
["hlo" "h??lo"]
["hello" "h?lo"]
["hello" "h???p"]]))
你可以看到这里正在执行:
http://ideone.com/8o4QdR
由于 Clojure 是一种使用递归的函数式语言,因此您会看到很多递归发生在那里。将其转换为更命令式的语言(如 C++)应该可以消除大部分递归,尤其是那些可以被循环替换的递归(这就是所有 recur 调用,只留下一个必要的递归使用)。