teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

1

コード例を追記

2015/11/18 03:09

投稿

yuba
yuba

スコア5570

answer CHANGED
@@ -3,4 +3,72 @@
3
3
 
4
4
  よく知られている(情報科学の講義で教わる)効率的な手法としてはKMP法、BM法というのがあります。その他に、BM法の改良型で実装しやすく効率も良い手法としてSunday法、またの名をクイックサーチと呼ぶものがあり、以前C#で書いたコードがあるので明日まだ質問が開いていたら載せます。
5
5
 
6
- .NET Frameworkには文字列探索のメソッド用意されてないんですよね。
6
+ .NET Frameworkには文字列探索のメソッド用意されてないんですよね。
7
+
8
+ --- 追記
9
+ ```c#
10
+ /// <summary>
11
+ /// byte配列の中からbyteパターンと一致する並びを検索する。
12
+ /// アルゴリズムはSunday法。
13
+ /// </summary>
14
+ /// <param name="pattern">探すパターン</param>
15
+ /// <param name="text">探索範囲となる配列</param>
16
+ /// <returns>発見した場合は開始位置、発見できなかった場合は-1</returns>
17
+ public static int SearchBytes(this byte[] text, byte[] pattern)
18
+ {
19
+ int patternLen = pattern.Length, textLen = text.Length;
20
+
21
+ // 移動量テーブルの作成
22
+ int[] qs_table = new int[byte.MaxValue + 1];
23
+
24
+ // デフォルト(パターン中に存在しないキャラクタが比較範囲の直後にあった)の場合、
25
+ // 次の比較範囲はそのキャラクタの次。(=比較範囲ずらし幅はパターン長+1)
26
+ for (int i = qs_table.Length; i-- > 0; ) qs_table[i] = patternLen + 1;
27
+
28
+ // パターンに存在するキャラクタが比較範囲の直後にあった場合、
29
+ // 次の比較範囲は、そのキャラクタとパターン中のキャラクタを一致させる位置に。
30
+ for (int n = 0; n < patternLen; ++n) qs_table[pattern[n]] = patternLen - n;
31
+
32
+ int pos;
33
+
34
+ // 移動量テーブルを用いて、文章の末尾に達しない範囲で比較を繰り返す
35
+ for (pos = 0; pos < textLen - patternLen; pos += qs_table[text[pos + patternLen]])
36
+ {
37
+ // 一致するか比較。一致したら、そのときの比較位置を返す。
38
+ if (CompareBytes(text, pos, pattern, patternLen)) return pos;
39
+ }
40
+
41
+ // 文章の末尾がまだ未比較なら、そこも比較しておく
42
+ if (pos == textLen - patternLen)
43
+ {
44
+ // 一致するか比較。一致したら、そのときの比較位置を返す。
45
+ if (CompareBytes(text, pos, pattern, patternLen)) return pos;
46
+ }
47
+
48
+ // 一致する位置はなかった。
49
+ return -1;
50
+ }
51
+
52
+ /// <summary>
53
+ /// 配列(pattern)が別の配列(text)に含まれているかを判定する。
54
+ ///
55
+ /// pos + patternLen が text.Length より大きかったり
56
+ /// pos や patternLen が 0 未満だったり、
57
+ /// needdleLen が pattern.Length より大きかったりすると
58
+ /// ArrayOutOfBoundException が発生する。
59
+ /// </summary>
60
+ /// <param name="text">この配列の pos 番目からを pattern と比較する</param>
61
+ /// <param name="pos">text のどこから比較するか</param>
62
+ /// <param name="pattern">この配列全体が、text の pos 番目からと一致しているかを判定する</param>
63
+ /// <param name="patternLen">patternのうち一致判定する長さ</param>
64
+ /// <returns></returns>
65
+ static bool CompareBytes(byte[] text, int pos, byte[] pattern, int patternLen)
66
+ {
67
+ for (int comparer = 0; comparer < patternLen; ++comparer)
68
+ {
69
+ if (text[comparer + pos] != pattern[comparer]) return false;
70
+ }
71
+ return true;
72
+ }
73
+
74
+ ```