none
マルチバイト文字の検出について RRS feed

  • 質問

  • お世話になっております。

    Power shell にて特定の文字列を50バイトずつ切り出して、次の処理に渡すということを以下の【Get-SubStringBytes】functionを利用して行っています。

    ============================================================

    function Get-SubStringBytes([String]$Text, [int]$StartIndex = 0, [int]$Length = 0) {
     $enc = [System.Text.Encoding]::Default
     $bytes = $enc.GetBytes($Text)
     return $enc.GetString($bytes, $StartIndex, $Length)
    }

    ============================================================

    上記の方法で50バイトずつ切り出すことは出来るのですが、50バイト目にマルチバイト文字が入っていると、切り出した際に、正しく文字を切り出すことが出来ず、次の処理に渡した際にエラーとなってしまいます。

    50バイト目の文字がマルチバイト文字かどうか判定する方法をご存知の方がいらっしゃいましたらご教示いただけないでしょうか?

    以上、よろしくお願い致します。

    2016年12月15日 5:11

回答

  • Azuleanさんのコメントで間違いを指摘されましたのでこの回答は無視してください。

    (指摘の通りでたとえば"メ"とかアウトですね...)

    <del>

    こんにちは。

    ここでおっしゃられているマルチバイト文字とはShift_JISの事だと思いますのでその前提でお話しします。

    Shift_JISでは2バイト文字の1バイト目が0x81~0x9f、0xe0~0xefになりますので、上記コードだと$bytes[50-1]の値がこれらの範囲にあるかで判定できると思います。

    雑に書くと

    ($bytes[49] -ge 0x81 -and $bytes[49] -le 0x9f) -or ($bytes[49] -ge 0xe0 -and $bytes[49] -le 0xef)

    な感じですね。

    </del>
    • 編集済み stknohg 2016年12月15日 15:25 内容に間違いがあったため
    • 回答としてマーク 渡邉洋平 2016年12月21日 6:51
    2016年12月15日 6:27
  • [Encoding]::GetEncodingメソッドが用意されています。codepage=0にて既定のエンコーディング、すなわち[Encoding]::Defaultと同じエンコーディングです。

    [System.Text.Encoding]::Default の代わりに

    $enc = [System.Text.Encoding]::GetEncoding(0, [System.Text.EncoderFallback]::ExceptionFallback, [System.Text.DecoderFallback]::ExceptionFallback)

    を使用すると、 $bytes = $enc.GetBytes($Text) にてShift-JISに変換できない文字が含まれている場合、および $enc.GetString($bytes, $StartIndex, $Length) にてShift-JISからUnicodeへ変換できない不正なシーケンスの場合に例外を発生させることができます。

    あとは適切に例外処理を行ってください。

    2016年12月15日 6:52
  • Shift_JISでは2バイト文字の1バイト目が0x81~0x9f、0xe0~0xefになりますので、上記コードだと$bytes[50-1]の値がこれらの範囲にあるかで判定できると思います。

    その判定では Shift_JIS の 2 バイト目である可能性を否定していません。
    基本的に先頭のバイトから判定していくしか、確実な判定はできないのが Shift_JIS なのでご注意を。

    対処策としては佐祐理さんが提案されているように、例外を出させて、1 バイト削ってリトライかなぁ。

    • 回答としてマーク 渡邉洋平 2016年12月21日 6:51
    2016年12月15日 13:48
  • あ、それは失礼しました。

    でしたら佐祐理さんの提案のやり方しかないですね。

    • 回答としてマーク 渡邉洋平 2016年12月21日 6:51
    2016年12月15日 14:48
  • マルチポストなのか、同様な質問を別の人が別のサイトに書いているのか分かりませんが、その別のサイトの URL を貼っておきます。

    https://teratail.com/questions/58936

    • 回答としてマーク 渡邉洋平 2016年12月21日 6:51
    2016年12月15日 15:58

すべての返信

  • Azuleanさんのコメントで間違いを指摘されましたのでこの回答は無視してください。

    (指摘の通りでたとえば"メ"とかアウトですね...)

    <del>

    こんにちは。

    ここでおっしゃられているマルチバイト文字とはShift_JISの事だと思いますのでその前提でお話しします。

    Shift_JISでは2バイト文字の1バイト目が0x81~0x9f、0xe0~0xefになりますので、上記コードだと$bytes[50-1]の値がこれらの範囲にあるかで判定できると思います。

    雑に書くと

    ($bytes[49] -ge 0x81 -and $bytes[49] -le 0x9f) -or ($bytes[49] -ge 0xe0 -and $bytes[49] -le 0xef)

    な感じですね。

    </del>
    • 編集済み stknohg 2016年12月15日 15:25 内容に間違いがあったため
    • 回答としてマーク 渡邉洋平 2016年12月21日 6:51
    2016年12月15日 6:27
  • [Encoding]::GetEncodingメソッドが用意されています。codepage=0にて既定のエンコーディング、すなわち[Encoding]::Defaultと同じエンコーディングです。

    [System.Text.Encoding]::Default の代わりに

    $enc = [System.Text.Encoding]::GetEncoding(0, [System.Text.EncoderFallback]::ExceptionFallback, [System.Text.DecoderFallback]::ExceptionFallback)

    を使用すると、 $bytes = $enc.GetBytes($Text) にてShift-JISに変換できない文字が含まれている場合、および $enc.GetString($bytes, $StartIndex, $Length) にてShift-JISからUnicodeへ変換できない不正なシーケンスの場合に例外を発生させることができます。

    あとは適切に例外処理を行ってください。

    2016年12月15日 6:52
  • Shift_JISでは2バイト文字の1バイト目が0x81~0x9f、0xe0~0xefになりますので、上記コードだと$bytes[50-1]の値がこれらの範囲にあるかで判定できると思います。

    その判定では Shift_JIS の 2 バイト目である可能性を否定していません。
    基本的に先頭のバイトから判定していくしか、確実な判定はできないのが Shift_JIS なのでご注意を。

    対処策としては佐祐理さんが提案されているように、例外を出させて、1 バイト削ってリトライかなぁ。

    • 回答としてマーク 渡邉洋平 2016年12月21日 6:51
    2016年12月15日 13:48
  • あ、それは失礼しました。

    でしたら佐祐理さんの提案のやり方しかないですね。

    • 回答としてマーク 渡邉洋平 2016年12月21日 6:51
    2016年12月15日 14:48
  • マルチポストなのか、同様な質問を別の人が別のサイトに書いているのか分かりませんが、その別のサイトの URL を貼っておきます。

    https://teratail.com/questions/58936

    • 回答としてマーク 渡邉洋平 2016年12月21日 6:51
    2016年12月15日 15:58
  • みなさまご返信いただきありがとうございます。

    佐祐理様からご回答いただいた内容にて対応できそうです。

    大変助かりました。

    2016年12月21日 6:57