【追記】本エントリには誤りが含まれています。(以下赤字取消線の部分など)
訂正記事
別に危険でも何でもないのですが、呆けていると嵌るなと思ったのでメモ。
例えばメッセージ出力などで、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
Ognac
単純に、vbがnを解釈すれば済む話だと思うのだが。
nを前提にしてデータ作成することもあるのにね。
Link | 2010年5月23日 21:44
オールトの雲
全くです。困ったもんです。
ただ歴史的に「\」を嫌っているのかなあ?とかとも思う。けど""はあるしなあ…とか。ああ、でもこれはCSVのエスケープと一緒か…。ややこしい。
Link | 2010年5月23日 22:56
よねけん
こんにちは。よねけんです。
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」が表示される
}
}
Link | 2010年5月24日 10:05
よねけん
#文字数制限に引っかかったのでコメントを分けています。
> では外出しさえしなければ良いかというと層でもない様で、
> 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#の言語仕様の違い(文字列リテラルの取り扱い)の話ですので、
その辺りを明確にしておいた方が、記事を読んだ人に誤解を与えずに済んでよいかなと思いました。
Link | 2010年5月24日 10:06
オールトの雲
コメントありがとうございます。気づいていませんでした。すみません…
そして… 仰るとおりですね。検証が甘く、文字リテラルと書式制御がごっちゃになっている様が露見しています。申し訳ありません。ご指摘ありがとうございます。
近日中に、まとめなおしてみたいと思います。
Link | 2010年5月28日 01:53
よねけん
返信ありがとうございます。
> 近日中に、まとめなおしてみたいと思います。
はい、楽しみにしております!
Link | 2010年5月28日 09:26
オールトの雲
[VB.NET] String.Formatの危険性(改) その0
元記事> http://ooltcloud.sakura.ne.jp/blog/201005/article_13015500.html
Link | 2010年6月6日 01:02