[VB.NET] String.Formatの危険性

2010年5月13日

 【追記】本エントリには誤りが含まれています。(以下赤字取消線の部分など)
訂正記事

別に危険でも何でもないのですが、呆けていると嵌るなと思ったのでメモ。

 例えばメッセージ出力などで、String.Format の書式文字列を外出し(ハードコードではなく定義ファイルなどに格納)して使用する場合、VB と C# で挙動が異なる場合があります。

例えば、

"AAAAnBBBB"

というメッセージを用意した場合、C#では、

AAAA
BBBB

と表示されますが、VBでは

AAAAnBBBB

となってしまいます。

これの何が恐ろしいかというと、C#er が何げに VB なシステムで上記のような書式を指定してしまった場合、意図したとおりに出力されないことを意味します。

では外出しさえしなければ良いかというと層でもない様で、C# のソースで String.Format を ハードコードしたものを DLL にして、それを VB で読ませた場合でも上記の結果になります。

なので言語間をまたぐ様なライブラリとか定義ファイルとかを作成する際は要注意です。

ちなみに、VB では n とかの代わりに ControlChars (http://msdn.microsoft.com/ja-jp/library/microsoft.visualbasic.controlchars_members.aspx) とか vbCrLf (http://msdn.microsoft.com/ja-jp/library/microsoft.visualbasic.constants_members.aspx) が用意されています。

しかしこれらは、CやC#のようにエスケープ文字ではなくあくまで定数なので、書式に組み込めません。不便です。
なのでどうしても、VB で 'n' のようなエスケープ文字を書式で使いたい、という場合は、正規表現クラスの Unescape メソッド (System.Text.RegularExpressions.Regex.Unescape) を使用することである程度実現できます。

' Imports System.Text.RegularExpressions.Regex は入れておく。
s = String.Format(Unescape("{0:00.00}naaaanbbbb"), 12.3)
WriteLine(s)

結果(VB2005)

  12.30
aaaa
bbbb





カテゴリー: C#, Program, VB.NET

Follow comments via the RSS Feed | Leave a comment | Trackback URL

7 Comments to "[VB.NET] String.Formatの危険性"

  1. Ognac

    単純に、vbがnを解釈すれば済む話だと思うのだが。
    nを前提にしてデータ作成することもあるのにね。

  2. オールトの雲

     全くです。困ったもんです。
     ただ歴史的に「\」を嫌っているのかなあ?とかとも思う。けど""はあるしなあ…とか。ああ、でもこれはCSVのエスケープと一緒か…。ややこしい。

  3. よねけん

    こんにちは。よねけんです。
    Ognacさんのところからやってきました。
    はじめてコメントいたします。よろしくお願いします。

    この記事で説明されているような現象は当方では再現できないのですが、
    どのように検証されたのでしょうか?

    > String.Format の書式文字列を外出し(ハードコードではなく定義ファイルなどに格納)して使用する場合、

    > 例えば、
    >"AAAAnBBBB"
    >というメッセージを用意した場合、C#では、
    > AAAA
    > BBBB
    >と表示されますが、

    と書かれていますが、そんなことはありません。
    外出しした「AAAAnBBBB」という文字列のnは、C#で読み込んだ場合も単なる文字列のnを意味します。
    String.Formatにとってもnは単なる文字列なので書式化された後に改行になったりはしません。

    記事に書かれている結果はどのように確認されたのでしょうか?
    (String.FormatやC#とは別のところでnが改行として認識されていませんか?)

    以下のようなコードで"n"は単なる文字列の"n"として扱われることを確認できます。
    using System;
    using System.IO;

    public class A
    {
    public static void Main()
    {
    ' 書式が書かれたファイルには「aaaanbbbb」と記述
    Console.WriteLine(string.Format(File.ReadAllText(書式が書かれたファイルのパス)));
    ' 画面には「aaaanbbbb」が表示される
    }
    }

  4. よねけん

    #文字数制限に引っかかったのでコメントを分けています。

    > では外出しさえしなければ良いかというと層でもない様で、
    > C# のソースで String.Format を ハードコードしたものを DLL にして、
    > それを VB で読ませた場合でも上記の結果になります。

    こちらもそのような現象は発生しませんが、どのように検証した結果なのでしょうか?
    私は以下のように検証しました。

    // C#で作成するDLL側
    using System;

    public class A
    {
    public static string Format()
    {
    return string.Format("aaaanbbbb");
    }
    }

    ' VBの呼び出し側
    Imports System

    Module X
    Sub Main()
    Console.WriteLine(A.Format())
    End Sub
    End Module

    ■処理結果
    aaaa
    bbbb

    --
    記事では使用している言語によって、String.Formatが"n"を改行と解釈したり、
    しなかったりするような印象を受けてしまいますが、
    実際には、VBとC#の言語仕様の違い(文字列リテラルの取り扱い)の話ですので、
    その辺りを明確にしておいた方が、記事を読んだ人に誤解を与えずに済んでよいかなと思いました。

  5. オールトの雲

     コメントありがとうございます。気づいていませんでした。すみません…

     そして… 仰るとおりですね。検証が甘く、文字リテラルと書式制御がごっちゃになっている様が露見しています。申し訳ありません。ご指摘ありがとうございます。
     近日中に、まとめなおしてみたいと思います。

  6. よねけん

    返信ありがとうございます。

    > 近日中に、まとめなおしてみたいと思います。

    はい、楽しみにしております!

  7. オールトの雲

    [VB.NET] String.Formatの危険性(改) その0

     元記事> http://ooltcloud.sakura.ne.jp/blog/201005/article_13015500.html

コメントを投稿する

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


«   »
 
Powered by Wordpress and MySQL. Theme by Shlomi Noach, openark.org