固定長文字列より指定位置の文字を取得

タグの編集
投稿者 JETT  (社会人) 投稿日時 2020/7/28 11:06:17
別のプログラムで生成されるファイルが、以下のようなファイル名であるとします。

"あああああ      AAAAいいいいいいいいいいいいいい  1111111111BBBBBBBBBB.txt"

いわゆる固定長?というのでしょうか、全角を2バイト・半角を1バイトとした書式で、
指定桁数に足りない箇所は半角スペースで右埋めされています。
また、対象文字はすべてShift_JISで表現可能な文字であるとします。

例えば、このファイル名の51バイト目から60バイト目(上でいう所の"1111111111"の部分)を
Stringとして取得するにはどういった方法があるでしょうか?
投稿者 るきお  (社会人) 投稿日時 2020/7/28 11:43:48
ShiftJISの文字コードの配列に変換して、51バイト目から60バイト目を抜き出して、再びShiftJISとして文字列に変換するという方法が素直だと思います。

#If NETCOREAPP Then
    '.NET Core/.NET 5以降の場合 
    System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance)
#End If

Dim value As String = "あああああ      AAAAいいいいいいいいいいいいいい  1111111111BBBBBBBBBB.txt"
Dim valurCharCodes As Byte() = System.Text.Encoding.GetEncoding("shift_jis").GetBytes(value)

Dim targetCharCodes = valurCharCodes.Skip(50).Take(10)
Dim result As String = System.Text.Encoding.GetEncoding("shift_jis").GetString(targetCharCodes.ToArray)


※.NET Core向けのコードも入れていますが、動作確認はしていません。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2020/7/28 16:47:35
> Skip(50).Take(10)
UTF-8 とは異なり、Shift_JIS は文字列の途中からだと、
それが全角文字の前半部なのか後半部なのかを調べられないので、
バイナリに対して、この方法で切り出すのは危険だと思います。

たとえば、51 バイト目が「全角文字の後半部」だった場合に、
それを誤って「全角文字の前半部」として扱われる可能性がありえますが、
その場合先頭文字だけでなく、そのあとに続く文字も化けてしまう恐れがあります。


【区切り位置を誤認しやすい文字列の例】 
"=" は Shift_JIS で 0x8181
"≠" は Shift_JIS で 0x8182
"a" は Shift_JIS で 0x8281
"b" は Shift_JIS で 0x8282



面倒でも、Shift_JIS 文字列の先頭から、文字数(Char あるいは Rune 単位)で
一文字ずつ拾い出していくなどして、半角なら +1、全角なら +2 として
カウントしていく方が良いかも知れません。
投稿者 JETT   (社会人) 投稿日時 2020/7/29 09:17:57
皆様、回答ありがとうございました。
ところで、 魔界の仮面弁士様ご指摘の件ですが、

>> Skip(50).Take(10)
> UTF-8 とは異なり、Shift_JIS は文字列の途中からだと、
>それが全角文字の前半部なのか後半部なのかを調べられないので、
>バイナリに対して、この方法で切り出すのは危険だと思います。

もし、51バイト目が必ず全角文字の前半部、または半角文字である、
(同様に、60バイト目が必ず全角文字の後半部、または半角文字である)
という前提があれば、るきお様の方法でも問題ないように思えるのですが、
如何でしょうか?
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2020/7/29 09:33:59
> もし、51バイト目が必ず全角文字の前半部、または半角文字である、
> (同様に、60バイト目が必ず全角文字の後半部、または半角文字である)
> という前提があれば、るきお様の方法でも問題ないように思えるのですが、
> 如何でしょうか?

文字の区切り位置が明確になっているのであれば、
バイト位置固定での切り出しで問題ありません。
投稿者 JETT  (社会人) 投稿日時 2020/7/29 12:10:39
魔界の仮面弁士様、ご回答ありがとうございました。
これで解決しました。