文字列検索(IndexOf)の使用方法

解決


なべぶた  2007-02-07 18:39:30  No: 97902

VB.net 2005 を使用しています。
以下の文字列検索で想像した結果になりません。
キャラクタセット関連の問題でしょうか?

        Dim s2 As String
        s2 = "abc゛xyz"    'cとxの間に全角文字が1つあります  Hex dump 61 62 63 81 4A 78 79 7A
        MsgBox(CStr(s2.IndexOf("a", 0)))   '0 になります
        MsgBox(CStr(s2.IndexOf("b", 0)))   '1 になります
        MsgBox(CStr(s2.IndexOf("c", 0)))   '-1 になります
        MsgBox(CStr(s2.IndexOf("゛", 0)))   '3 になります
        MsgBox(CStr(s2.IndexOf("x", 0)))   '4 になります
        MsgBox(CStr(s2.IndexOf("y", 0)))   '5 になります
        MsgBox(CStr(s2.IndexOf("z", 0)))   '6 になります
        MsgBox(CStr(s2.IndexOf("bc", 0)))   '-1 になります
        MsgBox(CStr(s2.IndexOf("abc", 0)))   '-1 になります

上記、"c" が絡むと -1 が返されます。
ご存知の方、ご教授頂けませんでしょうか。


通ってみた  2007-02-07 20:00:27  No: 97903

InStrではだめなんですか?
もしかして2005にはないんでしょうか・・・


Blue  2007-02-07 20:19:38  No: 97904

検索文字列が1文字なら

MsgBox(CStr(s2.IndexOf("c"c, 0))) 

で3って値になりますね。

> InStrではだめなんですか?
InStrだと正しい値が取れますね。
謎。。。


なべぶた  2007-02-07 21:33:04  No: 97905

皆様、ありがとうございます。

InStr で上手く行きますね。

全角文字が他の文字なら IndexOf でも上手くゆくので、UniCode関連(詳しくありません)など Encodingのお作法を私が知らないからかと思いました。

InStr にて対症します。


魔界の仮面弁士  2007-02-07 22:30:45  No: 97906

.NET だけでなく、データベースの Collate などにも言える話ですが、
Unicode の世界では、濁点・半濁点のように、直前の文字と組み合わせて
使われる文字は、一見、特殊な動作をすることがあります。

たとえば、「℃」という 1 文字は、U+00B0, U+0043 という
2 文字に分解したマッピング方法もあったりします。
http://homepage1.nifty.com/nomenclator/unicode/normalization.htm

そのせいかどうかはわかりませんが、たとえばこんな事も起きうるわけで。

s2 = "今日は12℃あります。"
MsgBox(CStr(s2.IndexOf("℃", 0)))       ' 5 (通常)
MsgBox(CStr(s2.IndexOf("C", 0)))        '-1 
MsgBox(CStr(s2.IndexOf("C゜", 0)))      ' 5 (合成文字扱い?)
MsgBox(CStr(s2.IndexOf("C゛", 0)))      '-1
MsgBox(CStr(s2.IndexOf("C゛゛", 0)))    ' 5 (なぜ?)

# このあたりは、Microsoft Access などでも、昔から同様の仕様であり、
#  x = "◎゛".CompareTo("●")
#  y = "◎゜".CompareTo("●゛")
# などに至っては、もう何が何やら。(^_^;)
http://www.asahi-net.or.jp/~ez3k-msym/comp/acccoll.htm

> InStr で上手く行きますね。
VBの場合、Option Compare 設定の影響を受けるので、これはこれで、
String.IndexOf とは異なる文字列処理方法が組み込まれているそうです。

ちなみに、こういう話もあったり。

  Dim S As String = "フ゛イ"

  '「ブイ」→「V」
  Dim A As String = S.Replace("ブイ", "V")                             'フ゛イ
  Dim B As String = Replace(S, "ブイ", "V", , , CompareMethod.Binary)  'フ゛イ
  Dim C As String = Replace(S, "ブイ", "V", , , CompareMethod.Text)    'Vイ

  '「フ」→「@」
  Dim D As String = S.Replace("フ", "@")                               '@イ
  Dim E As String = Replace(S, "フ", "@", , , CompareMethod.Binary)    '@イ
  Dim F As String = Replace(S, "フ", "@", , , CompareMethod.Text)      '@イ

  '「フ゛」→「*」
  Dim G As String = S.Replace("フ゛", "*")                             '*イ
  Dim H As String = Replace(S, "フ゛", "*", , , CompareMethod.Binary)  '*イ
  Dim I As String = Replace(S, "フ゛", "*", , , CompareMethod.Text)    '*イ

  '「フ゛」→「*」
  Dim J As String = S.Replace("゛", "%")                             'フ%イ
  Dim K As String = Replace(S, "゛", "%", , , CompareMethod.Binary)  'フ%イ
  Dim L As String = Replace(S, "゛", "%", , , CompareMethod.Text)    'フ%イ


なべぶた  2007-02-07 23:15:23  No: 97907

ありがとうございます。

基本的な文字列操作のような案件でしたが、ご説明頂いたような深淵(コードに対する考え方など)がありそうだと感じたので質問させていただきました。

まさに「℃」という 1 文字を分割するかどうかも考え方によると思います。

簡単そうですが、ここまで(これ以外にも)理解しないと正しいプログラムが組めないと言うことを痛感します。


我龍院  2007-02-08 00:21:56  No: 97908

なるほど、複雑なものですね。(メモ、メモ..)
ところで、
>>MsgBox(CStr(s2.IndexOf("c", 0)))

MsgBox(CStr(s2.IndexOf(CType("c", Char), 0)))
MsgBox(CStr(s2.IndexOf("c"c, 0))) 
これの方が正しい気がするのだがなんとなく(気のせいかな)
String.IndexOf (Char, Int32) を呼び出すか、
String.IndexOf (String, Int32)を呼び出すかの違いなんですが、 
で、こうすると、Char単位では正確に取得出来ますな。
でもやっぱり、"bc","abc"の文字列はダメなんで、
この場合、何の解決にもなりませんが。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加