検索される文字列をs
、検索する文字列をt
とおいたとき、次のようにループを書けばバグは発生しない。
for (int i = 0; i + t.size() <= s.size(); i++) { if (s.substr(i, t.size()) == t) { /* */ } }
ポイントは半開区間[l, r)
で考えること。
|S| = S.size()
とすると、s
の参照可能な区間は[0, |s|)
であり、s
のi
文字目から|t|
文字を参照するので参照したい範囲は[i, i + |t|)
。つまり、[0, |s|)
が[i, i + |t|)
を包含しなければならないので、以下の条件式を満たす必要がある。
i >= 0
i + |t| <= |s|
i
の定義により1.は必ず満たすので、2.のみをループの継続条件にすればいい。
substr()
の性質から、わざわざ上のように書く必要はない。しかし、上の書き方は通常の配列にも対応できる。
for (int i = 0; i + t.size() <= s.size(); i++) { bool match = true; for (int j = 0; j < t.size(); j++) { if (t[j] != s[i + j]) match = false; } if (match) { /* */ } }
substr()
の性質を利用したコードをそのまま配列に流用すると、配列外参照が発生する可能性がある(|t| = 1
のときだけ発生しない)。
// OK for (int i = 0; i < s.size(); i++) { if (s.substr(i, t.size()) == t) { } } // NG for (int i = 0; i < s.size(); i++) { bool match = true; for (int j = 0; j < t.size(); j++) { if (t[j] != s[i + j]) match = false; } if (match) { } }