StrConvで全角→半角→全角変換した場合に元に戻らない文字がある

解決


すみた  2009-08-24 21:52:09  No: 142444

全角文字を半角に変換して処理を行い、その結果を全角文字に変換するようなプログラムを作成しています。
Dim value As String

(略)

'半角に変換
value = StrConv(value, VbStrConv.Narrow)

(ここに処理が入る)

'全角に変換
value = StrConv(value, VbStrConv.Wide)

ここで気付いたのですが、シングルクォーテーションを全角→半角→全角に変換すると、以下のようになることが分かりました。
・全角文字"’"を半角文字に変換→"'"
・全角文字"キ"を半角文字に変換→"'"
  (いずれも同じ半角文字"'"に変換される)
・半角文字"'"を全角文字に変換→"キ"
  ("’"には変換されない)
つまり、全角文字"’"を全角→半角→全角変換を行うと、以下のようになってしまいます。
StrConv(StrConv("’", VbStrConv.Narrow), VbStrConv.Wide) → "キ"
これは、変換時に何か考慮しなければならないでしょうか?
また、このような文字は他にもあるでしょうか?
ちなみにVB2008でVistaを使用しています。
よろしくお願いします。


すみた  2009-08-24 22:02:26  No: 142445

上記で記入した半角文字"'"を全角文字に変換したときの文字が文字化けしてしまいましたが、
AscW関数で取得したこの文字の文字コードはFF07でした。
よろしくお願いします。


魔界の仮面弁士  2009-08-25 00:01:53  No: 142446

> これは、変換時に何か考慮しなければならないでしょうか?
「どのように変換してほしいのか」は、ケースバイケースですので、
その結果が求めるもので無い場合、自身で置換する必要があるでしょう。

> また、このような文字は他にもあるでしょうか?
「どのようになって欲しい」のかは、本人にしか分かりませんので、
答えにくい所ですが、一般論として「ある」と答えておきます。

VbStrConv.Wide/Narrow が求めるところは、「対応する半角文字/全角文字がある組み合わせ」の
変換に限ります。

ところが一部の組み合わせでは、半角全角それぞれの文字が一対一に対応しておらず、
一対多の組み合わせだったり、一対零の組み合わせになるものがあります。

たとえば、[文字コード表]の文字セットを Unicode にして、
「quot」という名前を含む文字を検索してみてください。
似たような記号が、幾つか並んでいるのが見えるかと思います。
http://windowshelp.microsoft.com/Windows/ja-JP/help/7c481264-5509-4bce-b290-7f41d09545071041.mspx

通常、半角のアポストロフィ/シングルクォーテーションといえば、
   「'」Unicode=0027, Shift_JIS=27  《Apostrophe》文字幅 Narrow
の文字を想像するかと思います。

一方、全角アポストロフィ/シングルクォーテーションといえば、
  「’」Unicode=2019, Shift_JIS=8166《Right Single Quotation Mark》文字幅 Ambigous
が思い浮かぶかも知れません。

ところが、実際にはこの逆向きの
  「‘」Unicode=2018, Shift_JIS=8165《Left Single Quotation Mark》文字幅 Ambigous
という記号もありますし、その中間に打たれる文字もあります。
        Unicode=FF07, Shift_JIS=FA56《Fullwidth Apostrophe》文字幅 Full Width
Unicode 上では、他にも似た形状の記号が幾つか定義されています(275B, 275C, 201B など)。

さて、実際に変換してみると、すみたさんが実際に経験されたように、
27 の文字と FF07 の文字が、相互に対応する事が分かるかと思います。

ここで、それぞれの文字の《名称》を見てみると、Unicode の定義上において、
ChrW(&HFF07)《Fullwidth Apostrophe》を半角化したものが、
ChrW(&H27)  《Apostrophe》 に対応する事は、不自然な事ではありませんよね。

しかし、ChrW(&H2019)「’」を半角変換した場合も、
ChrW(&H27)「'」《Apostrophe》になる事も期待されるかと思います。

このように、変換候補が一対多になってしまうような状況においては、
「半角化→全角化→半角化」や「全角化→半角化→全角化」という処理は
元の文字に戻らない事がありえます。

これと同様の事が、「"」「”」「“」などに対しても言えます。

他に怪しい物として、「\」と「¥,\」などが知られています。5C に割り当てられた文字は、
日本では円マークで知られますが、米国ではバックスラッシュとして知られています。
(日本では、ファイルのフォルダパスの区切りは円記号ですが、米国ではバックスラッシュです)

そして Unicode においては、
   「\」Unicode=005C,(Shift_JIS=5C) 《Reverse Solidus》文字幅 Narrow
  「\」Unicode=FF3C, Shift_JIS=815F《Fullwidth Reverse Solidus》文字幅 Full Width
        Unicode=00A5,(Shift_JIS=5C) 《Yen Sign》文字幅 Narrow
  「¥」Unicode=FFE5, Shift_JIS=818F《Fullwidth Yen Sign》文字幅 Full Width
と定義されています。

日本においては、「\」と「¥」が対応して欲しいかも知れませんが、他の国では違うかも知れません。
たとえば、日本と韓国での変換結果を比べてみると、
  Dim s0 As String = "¥"  '…ChrW(&HFF5E)
  Dim ja_jp = StrConv(s0, VbStrConv.Narrow, &H411)  '…ChrW(&5C)
  Dim ko_KR = StrConv(s0, VbStrConv.Narrow, &H412)  '…ChrW(&HFF5E)
のように、違った結果を返します。

ロケール依存の話としては、半角ハングルなどもあります。
  Dim s0 As String = ChrW(&HFFB1)  '《Halfwidth Hangul Letter Mieum》
  Dim ja_jp = StrConv(s0, VbStrConv.Narrow, &H411)  'ChrW(&FF1F) 「?」《Fullwidth Question Mark》
  Dim ko_KR = StrConv(s0, VbStrConv.Narrow, &H412)  'ChrW(&H3141)《Fullwidth Question Mark》
こういった、日本で使われない文字についても注意が必要です。

また、歴史的な経緯によって変換結果が曖昧になる物もあります。一例としては、
        Unicode=3094, Shift_JIS=無し《Hiragana Letter Vu》文字幅 Wide
等です。

御存じのように、ひらがなには対応する半角文字が存在しません。そのため、
半角カタカナに変換するという実装が行われる事も少なくありません。

結果として、日本語環境下においては
  x = ChrW(&H3094)
  y = StrConv(x, VbStrConv.Narrow)
の実行結果は、
  y = ChrW(&HFF73) & ChrW(&HFF9E)  '半角の「ウ」+半角の「゛」
という 2 文字になります。

既にカタカナ化していますから、全角変換した
  z = StrConv(y, VbStrConv.Wide)
が、平仮名である x に戻る事はなく、
  「ヴ」Unicode=30F4, Shift_JIS=8394《Katakana Letter Vu》文字幅 Wide
になります。これも、半角/全角の結果が一致しない例と言えるでしょう。

さらに注意すべきは、この結果が「ウ゛」ではなく「ヴ」であるという事です。
しかし、半角 2 文字を 1 文字ずつ変換すれば、「ウ゛」になります。

では、さらにその逆変換はどうでしょうか?
  Dim a As String = StrConv("ヴ", VbStrConv.Narrow)
  Dim b As String = StrConv("ウ゛", VbStrConv.Narrow)
  Dim c As String = StrConv(a, VbStrConv.Narrow)
  Dim d As String = StrConv(b, VbStrConv.Narrow)

予想できるかと思いますが、上記において c と d は同じ結果となります。
これもまた、半角/全角を繰り返した結果が、一致しなくなる例と言えますね。

さらに言えば、Unicode における全角濁点記号は、
  「゛」Unicode=309B, Shift_JIS=814A《Katakana-Hiragana Voiced Sound Mark》文字幅 Wide
だけではありません。合成記号文字
        Unicode=3099, Shift_JIS=無し《Combining Katakana-Hiragana Voiced Sound Mark》文字幅 Wide
という物もあったりするので、さらにややこしいところです。

こうした文字は他にもありますが、これは .NET だけの問題ではありません。
.NET 以前の VB でも、同じ問題を抱えていましたし、OS による違いもありました。

たとえば、旧 VB における StrConv では、このような結果になっていました。
&H の部分は、Asc/Chr関数で変換される Shift_JIS のコードです。

&H0022["] → vbWide → &HFA57
&H0027['] → vbWide → &HFA56
&H005C[\] → vbWide → &H5C[\]
&H818F[¥] →vbNarrow→ NT/2000では &H5C[\]、9X系では変化無し(&H818F[¥])
&H815F[\] →vbNarrow→ &H815F[\]
&H8165[‘] →vbNarrow→ &H27[']
&H8166[’] →vbNarrow→ &H27[']
&HFA56 →vbNarrow→ NT/2000では &H27[']、9X系では変化無し(&HFA56)
&H8167[“] →vbNarrow→ &H22["]
&H8168[”] →vbNarrow→ &H22["]
&HFA57 →vbNarrow→ NT/2000では &H22["]、9X系では変化無し(&HFA57)


魔界の仮面弁士  2009-08-25 00:07:47  No: 142447

一か所訂正。文字の説明が間違っていました。

> ロケール依存の話としては、半角ハングルなどもあります。
>   Dim s0 As String = ChrW(&HFFB1)  '《Halfwidth Hangul Letter Mieum》
>   Dim ja_jp = StrConv(s0, VbStrConv.Narrow, &H411)  'ChrW(&FF1F) 「?」《Fullwidth Question Mark》
>   Dim ko_KR = StrConv(s0, VbStrConv.Narrow, &H412)  'ChrW(&H3141)《Fullwidth Question Mark》

上記の ko_KR の行は、
    Dim ko_KR = StrConv(s0, VbStrConv.Narrow, &H412)  'ChrW(&H3141)《Hangul Letter Mieum》
と読み替えてください。

# ちなみに FFB1/3141 は、「□」に似たような文字です。


魔界の仮面弁士  2009-08-25 03:01:44  No: 142448

済みません。もう一か所間違えていました。m(_ _;)m

>  Dim a As String = StrConv("ヴ", VbStrConv.Narrow)
>  Dim b As String = StrConv("ウ゛", VbStrConv.Narrow)
>  Dim c As String = StrConv(a, VbStrConv.Narrow)
>  Dim d As String = StrConv(b, VbStrConv.Narrow)

c と d の行は、VbStrConv.Narrow ではなく VbStrConv.Wide と読み替えてください。


すみた  2009-08-25 20:04:23  No: 142449

魔界の仮面弁士さま、詳しい解説ありがとうございました。
これらのことを考慮する必要があるということですね。
大変勉強になりました。ありがとうございました。
このスレッドは終了させていただきます。


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

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






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