文字コードの判定についてNo.04078
舩橋幸雄 さん 04/02/03 15:47
 
舩橋です。

if(rightstr($idxdir,1)!="\\") という判定で、$idxdirに格納されている文字列が"
表"の時、else のルートに制御が渡ってしまいました。

文字コードを調べたところ"表"の文字コードは、0x955c(S-JIS)のため"\"の
0x5cと区別がつかなかったようです。

文字列の最後が、2バイトコードか否かを判定する良い方法は無いでしょうか?

[ ]
RE:04078 文字コードの判定についてNo.04081
杉浦 まさき さん 04/02/04 00:17
 
舩橋さん、こんばんは。
杉浦 まさきです。

>文字列の最後が、2バイトコードか否かを判定する良い方法は無いでしょうか?

最後の文字の1文字前が2バイトコードの1バイト目かどうかを
調べるのが素直な方法だと思います。

#len = strlen($s);
if (#len >= 2) {
 && char(midstr($s, #len - 2, 1)

[ ]
RE:04081 文字コードの判定についてNo.04082
杉浦 まさき さん 04/02/04 01:48
 
すみません。途中で投稿してしまいました。
しかも半角カタカナ文字のことをすっかり忘れていました。
半角カタカナを考慮すると最大3文字までバックトラックを
かける必要がありますね(多分(^^;)。

なお、下記のコメント内で
リード文字は 2バイト文字の1バイト目になりうる文字
トレイル文字は2バイト文字の2バイト目になりうる文字
を意味します。

#is_2byte_char = 0;

// このルーチンではShift-JIS文字列として意味を持つ
// 文字列に対してのみ有効です。
#len = strlen($s);
if (#len >= 2) {
  #c1 = char(rightstr($s, 1));
  call IsCharTrailByte #c1;
  if (##return) {
    // 最後の文字がトレイル文字になりうる
    // 文字だった場合
    call IsCharOneByteStuff #c1;
    if (!##return) {
      // トレイル文字にしかなりえない文字だった
      #is_2byte_char = 1;
    } else {
      #c2 = char(midstr($s, #len - 2, 1));
      call IsCharLeadByte #c2;
      if (##return) {
        // 最後から2番目の文字がリード文字に
        // なりうる文字だった場合
        // (この時点で #c2 は1バイト文字ではありえない)
        if (#len == 2) {
          // 全部で2バイトしかないため2バイト文字であることが
          // 確定する。
          #is_2byte_char = 1;
        } else {
          call IsCharTrailByte #c2;
          if (!##return) {
            // #c2 はトレイル文字になりえないため、
            // #c1 はトレイル文字であることが確定。
            #is_2byte_char = 1;
          } else {
            call IsCharLeadByte char(midstr($s, #len - 3, 1));
            if (!##return) {
              // 最後から3バイト目の文字がリード文字
              // ではないことから、#c2 がトレイル文字
              // でないことが確定し、
              // #c1 がトレイル文字であることが
              // 確定する。
              #is_2byte_char = 1;
            }
            // 最後から3バイト目の文字がリード文字に
            // なりうる文字の場合、#c2 が1バイト文字では
            // ありえないことから #c2 がトレイル文字である
            // ことが確定し、#c1 が1バイト文字であることが
            // 確定する。
          }
        }
      }
    }
  }
}

// 文字種を返すサブルーチン群:

// リード文字になりうる文字かどうかを返す
IsCharLeadByte:
  return (##1 >= 0x81 && ##1 <= 0x9F) ||
         (##1 >= 0xE0 && ##1 <= 0xFC);

// トレイル文字になりうる文字かどうかを返す
IsCharTrailByte:
  return (##1 >= 0x40 && ##1 <= 0xFC && ##1 != 0x7F);

// 1バイト文字になりうるかどうかを返す
// なお、IsCharLeadByte と IsCharOneByteStuff が
// 同一文字コードに対してともに 1 を返すことはない
IsCharOneByteStuff:
  return (##1 >= 0x0 && ##1 <= 0x7E) ||
         (##1 >= 0xA1 && ##1 <= DF);


[ ]
RE:04082 文字コードの判定についてNo.04083
舩橋幸雄 さん 04/02/04 13:25
 
杉浦 まさき殿

舩橋です。
回答ありがとうございました。
参考にさせていただきます。

>すみません。途中で投稿してしまいました。
>しかも半角カタカナ文字のことをすっかり忘れていました。
>半角カタカナを考慮すると最大3文字までバックトラックを
>かける必要がありますね(多分(^^;)。
>
>なお、下記のコメント内で
>リード文字は 2バイト文字の1バイト目になりうる文字
>トレイル文字は2バイト文字の2バイト目になりうる文字
>を意味します。
>
>#is_2byte_char = 0;
>
>// このルーチンではShift-JIS文字列として意味を持つ
>// 文字列に対してのみ有効です。
>#len = strlen($s);
>if (#len >= 2) {
>  #c1 = char(rightstr($s, 1));
>  call IsCharTrailByte #c1;
>  if (##return) {
>    // 最後の文字がトレイル文字になりうる
>    // 文字だった場合
>    call IsCharOneByteStuff #c1;
>    if (!##return) {
>      // トレイル文字にしかなりえない文字だった
>      #is_2byte_char = 1;
>    } else {
>      #c2 = char(midstr($s, #len - 2, 1));
>      call IsCharLeadByte #c2;
>      if (##return) {
>        // 最後から2番目の文字がリード文字に
>        // なりうる文字だった場合
>        // (この時点で #c2 は1バイト文字ではありえない)
>        if (#len == 2) {
>          // 全部で2バイトしかないため2バイト文字であることが
>          // 確定する。
>          #is_2byte_char = 1;
>        } else {
>          call IsCharTrailByte #c2;
>          if (!##return) {
>            // #c2 はトレイル文字になりえないため、
>            // #c1 はトレイル文字であることが確定。
>            #is_2byte_char = 1;
>          } else {
>            call IsCharLeadByte char(midstr($s, #len - 3, 1));
>            if (!##return) {
>              // 最後から3バイト目の文字がリード文字
>              // ではないことから、#c2 がトレイル文字
>              // でないことが確定し、
>              // #c1 がトレイル文字であることが
>              // 確定する。
>              #is_2byte_char = 1;
>            }
>            // 最後から3バイト目の文字がリード文字に
>            // なりうる文字の場合、#c2 が1バイト文字では
>            // ありえないことから #c2 がトレイル文字である
>            // ことが確定し、#c1 が1バイト文字であることが
>            // 確定する。
>          }
>        }
>      }
>    }
>  }
>}
>
>// 文字種を返すサブルーチン群:
>
>// リード文字になりうる文字かどうかを返す
>IsCharLeadByte:
>  return (##1 >= 0x81 && ##1 <= 0x9F) ||
>         (##1 >= 0xE0 && ##1 <= 0xFC);
>
>// トレイル文字になりうる文字かどうかを返す
>IsCharTrailByte:
>  return (##1 >= 0x40 && ##1 <= 0xFC && ##1 != 0x7F);
>
>// 1バイト文字になりうるかどうかを返す
>// なお、IsCharLeadByte と IsCharOneByteStuff が
>// 同一文字コードに対してともに 1 を返すことはない
>IsCharOneByteStuff:
>  return (##1 >= 0x0 && ##1 <= 0x7E) ||
>         (##1 >= 0xA1 && ##1 <= DF);
>

[ ]
RE:04083 文字コードの判定についてNo.04084
Arimac さん 04/02/04 13:58
 
バックトラックは3文字じゃ済まないと思います。
以下のリンクを参考にした方が良いかも
http://www.maruo.co.jp/hidesoft/2/x15143_.html#15143

[ ]
RE:04084 文字コードの判定についてNo.04086
杉浦 まさき さん 04/02/04 21:54
 
Arimac さん、こんばんは。
杉浦 まさきです。

>バックトラックは3文字じゃ済まないと思います。

確かにこれで正しいかどうかは自信ないんですけど(^^;、
「Shift-JIS 文字の文字列として意味を持つものにのみ有効」
「(任意の位置ではなく)最後の文字についての判定である」
というだけでは3文字に制限できないんでしょうかねぇ。。。
自分のコメントを読み直しても、特にロジックに穴が
あるようには思えないんですけど。。。う〜ん。

[ ]
RE:04086 文字コードの判定についてNo.04087
Arimac さん 04/02/04 23:42
 
文字コードを分類してA〜Cで表わすとすると
A:1バイト
B:2バイトのどちらか
C:1バイト又は2バイトの後

具体的には
00-3F   A
40-7E   C
7F      A
80      C
81-9F   B
A0-DF   C
E0-FC   B
FD-FF   A

可能な組み合わせは
A
C
BB
BC

そこで以下の場合は先頭まで戻らないとCが1バイト文字かどうかは分からない事にな
ります。
BBBBBC
BBBBC

[ ]
RE:04087 文字コードの判定についてNo.04088
JRくん さん 04/02/05 00:49
 

いぢわるな例ですが、

http://homepage2.nifty.com/jr-kun/hidemaru_qa/3_string.html#DOUBLE


[ ]
RE:04088 文字コードの判定についてNo.04089
でるもんた さん 04/02/05 07:18
 
でるもんたです。

どこまでも必要に応じてトラックバックするコードがここにあります↓
http://www.miri.ne.jp/~izumi/lang/001.html
C言語ですが。

[ ]
RE:04089 文字コードの判定についてNo.04090
杉浦 まさき さん 04/02/05 11:54
 
既にこんなにコメントが…(笑)。

それはともかく、コメントの説明で最後から3文字目が
「リード文字になりえる」ことと「リード文字で確定」
ということを思いっきり混同していました。
#↑今朝の通勤中にやっと気づきました(^^;。

というわけで修正版サンプルは家に帰った後でアップします。


[ ]
RE:04090 文字コードの判定についてNo.04095
杉浦 まさき さん 04/02/06 00:55
 
>というわけで修正版サンプルは家に帰った後でアップします。

何だか久しぶりに頭を使ったような気がしますが(^^;、
それはともかく以下のIsLast2ByteCharサブルーチンで
多分OKだと思います。
ご協力いただいた方どうもありがとうございましたm(_ _)m。
#再帰呼び出しで処理すると call のネスト制限に
 引っかかる恐れがあるので、今回は Arimac さんの
 発言で引用されていた秀まるおさんのコードを参考にしました。

// テストコード開始
$str[0] = "abcdefg";
$str[1] = "abcdef";
$str[2] = "あいうえお";
$str[3] = "aいcえe";
$str[4] = "a";
$str[5] = "ヤヤヤヤ";
$str[6] = "ヤヤヤヤa";
$str[7] = "";

#a = 0;
while (#a < 8) {
    call IsLast2ByteChar $str[#a];
    if (##return) {
        message $str[#a] + " の最後は2バイト文字";
    } else {
        message $str[#a] + " の最後は1バイト文字";
    }
    #a = #a + 1;
}
endmacro;
// テストコード終了

IsLast2ByteChar:
    ##len = strlen($$1) - 1;
    ##pos = ##len;
    while (##pos > 0) {
        // ascii() に2バイト文字の1バイト目のみを渡すと
        // 自動で2バイト文字と判定される
        // (ex. ascii("\x81") == 0x8100)
        if (ascii(midstr($$1, ##pos - 1, 1)) < 0x100) {
            break;
        }
        ##pos = ##pos - 1;
    }
    return (##len - ##pos) % 2;


[ ]
RE:04095 文字コードの判定についてNo.04101
舩橋幸雄 さん 04/02/06 12:45
 
舩橋です。

ありがとうございました。さっそくマクロに組み込みました。
(ロジックの理解はこれからですが)


>>というわけで修正版サンプルは家に帰った後でアップします。
>
>何だか久しぶりに頭を使ったような気がしますが(^^;、
>それはともかく以下のIsLast2ByteCharサブルーチンで
>多分OKだと思います。
>ご協力いただいた方どうもありがとうございましたm(_ _)m。
>#再帰呼び出しで処理すると call のネスト制限に
> 引っかかる恐れがあるので、今回は Arimac さんの
> 発言で引用されていた秀まるおさんのコードを参考にしました。
>
>// テストコード開始
>$str[0] = "abcdefg";
>$str[1] = "abcdef";
>$str[2] = "あいうえお";
>$str[3] = "aいcえe";
>$str[4] = "a";
>$str[5] = "ヤヤヤヤ";
>$str[6] = "ヤヤヤヤa";
>$str[7] = "";
>
>#a = 0;
>while (#a < 8) {
>    call IsLast2ByteChar $str[#a];
>    if (##return) {
>        message $str[#a] + " の最後は2バイト文字";
>    } else {
>        message $str[#a] + " の最後は1バイト文字";
>    }
>    #a = #a + 1;
>}
>endmacro;
>// テストコード終了
>
>IsLast2ByteChar:
>    ##len = strlen($$1) - 1;
>    ##pos = ##len;
>    while (##pos > 0) {
>        // ascii() に2バイト文字の1バイト目のみを渡すと
>        // 自動で2バイト文字と判定される
>        // (ex. ascii("\x81") == 0x8100)
>        if (ascii(midstr($$1, ##pos - 1, 1)) < 0x100) {
>            break;
>        }
>        ##pos = ##pos - 1;
>    }
>    return (##len - ##pos) % 2;
>

[ ]