TStrings::CommaTextは半角スペースも区切り文字とみなす
エントリのタイトルがすべてです。前の記事で、CSVファイルアクセスクラスを作ってみていたのですが、VCLのTStrings::CommaTextプロパティが、Commaだけでなく、Spaceも区切り文字とみなすことが分かりました。ややこしいプロパティ名しやがってこのー。
CSVファイルアクセスクラス - 涼の成長記録
CommaTextのリファレンスを読むと、しれっとこんなこと書いてあります。
CommaText を割り当てる場合,値は SDF 書式付きテキストとして解析されます。SDF 形式の場合,文字列はスペースまたはカンマで区切られ,任意で二重引用符で囲まれます。
そもそも、SDF書式付きテキストって何ですか。SDFってなんですか。Self-Defense Forceで自衛隊ですか。Standard Delay Formatなんですか、標準遅延フォーマットなんですか、そうですか、聞いたことありませんよ、情報弱者の私には到底理解できません。
Standard Delay Format - Wikipedia, the free encyclopedia
嘆いていても始まらないので、別の方法を探していたのですが、TStringsには、Delimiterという心強いプロパティがおりました。私がうだうだ言うより、コードを見てもらった方が早いです。
こうやって取ると、半角スペースが区切り文字とみなされてしまうので、
TStringList *file = new TStringList; // ファイル全体分のデータ。 TStringList *line = new TStringList; // 一行分のデータ。 file->LoadFromFile(m_FilePath); line->CommaText = file->Strings[0];
Delimiterプロパティにコンマを指定し、StrictDelimiterをtrueにしておきます。値の取り出しは、CommaTextでなく、DelimitedTextで取り出します。
TStringList *file = new TStringList; // ファイル全体分のデータ。 TStringList *line = new TStringList; // 一行分のデータ。 file->LoadFromFile(m_FilePath); // 区切り文字を明示的に指定。(カンマ) line->Delimiter = ','; // Delimiterプロパティに指定した区切り文字だけを区切り文字とみなす。 line->StrictDelimiter = true; // CommaTextでなく、DelimitedTextで取り出す。 line->DelimitedText = file->Strings[0];
以上を踏まえると、以前のTCsvFileAccess.cppは、以下のようになります。
/*! @file TCsvFileAccess.cpp @brief CSVファイルアクセスクラスの実装 */ #include <vcl.h> #pragma hdrstop #include <IOUtils.hpp> #include <vector> #include "TCsvFileAccess.h" #pragma package(smart_init) namespace Common { namespace FileAccess { //------------------------------------------------------------------------------ // コンストラクター //------------------------------------------------------------------------------ __fastcall TCsvFileAccess::TCsvFileAccess(const UnicodeString &filePath) : m_FilePath(filePath) { // フォルダーを作成しておく。 try { ForceDirectories(TPath::GetDirectoryName(m_FilePath)); } catch (...) { // 例外もぐもぐ。。 } } //------------------------------------------------------------------------------ // ファイルがあればtrueを返す //------------------------------------------------------------------------------ bool __fastcall TCsvFileAccess::isFileExist() { return FileExists(m_FilePath); } //------------------------------------------------------------------------------ // 読み込み。 //------------------------------------------------------------------------------ bool __fastcall TCsvFileAccess::read(CSV_VECTOR &array) { // 読込むファイルが無ければ異常 if (!FileExists(m_FilePath)) { return false; } TStringList *line = new TStringList; // 一行分のデータ。 TStringList *file = new TStringList; // ファイル全体分のデータ。 try { // 項目数エラーや、異常値等で簡単に例外が発生する。 file->LoadFromFile(m_FilePath); line->Delimiter = ','; line->StrictDelimiter = true; for (unsigned int i = 0; i < array.size(); i++) { line->DelimitedText = file->Strings[i]; for (unsigned int j = 0; j < array.at(i).size(); j++) { array.at(i).at(j) = line->Strings[j]; } } } catch (...) { delete line; delete file; return false; } delete line; delete file; return true; } //------------------------------------------------------------------------------ // 書き込み。 //------------------------------------------------------------------------------ void __fastcall TCsvFileAccess::write(const CSV_VECTOR &array) { TStringList *line = new TStringList; // 一行分のデータ。 TStringList *file = new TStringList; // ファイル全体分のデータ。 file->Clear(); for (unsigned int row = 0; row < array.size(); row++) { line->Clear(); for (unsigned int col = 0; col < array.at(row).size(); col++) { line->Add(array.at(row).at(col)); } file->Add(line->CommaText); } file->SaveToFile(m_FilePath); delete line; delete file; } } // namespace FileAccess } // namespace Common
いやー、プログラミングって楽しいですね。(こう言えば許されると思っている。)
ではでは。