INI に似た構文だと思いますが、セクションがないため、解析するには次のようにします。
ファイルの解析に使用するクラスのコンストラクター (たとえば) では、次のようにします。
- を作成し
Dictionary<string, string>
、そこに解析された値を保持します (キーの大文字と小文字を区別しない比較子を指定します)。
- ファイルの各行を読み、空白行をスキップします (サポートしたい場合はコメント行)。
- 各文字列行で最初の「=」文字を検索します。その左側の部分がオプションの名前で、右側の部分が値です。
- それらを辞書に保存します。
GetValue()
メソッドでこれを行います:
- 指定されたキーの辞書を検索して返します。
- 指定された値を持つキーがない場合は、単にデフォルト値を返します。
これは、単純な INI パーサーの可能な実装です (セクション名が必要ない場合は、空の文字列を渡すだけです)。
using namespace System;
using namespace System::Text;
using namespace System::IO;
using namespace System::Globalization;
using namespace System::Collections::Generic;
namespace Testy
{
ref class IniParser
{
public:
IniParser()
{
_values = gcnew Dictionary<String^, Dictionary<String^, String^>^>(
StringComparer::InvariantCultureIgnoreCase);
}
IniParser(String^ path)
{
_values = gcnew Dictionary<String^, Dictionary<String^, String^>^>(
StringComparer::InvariantCultureIgnoreCase);
Load(path);
}
void Load(String^ path)
{
String^ currentSection = "";
for each (String^ line in File::ReadAllLines(path))
{
if (String::IsNullOrWhiteSpace(line))
continue;
if (line->StartsWith(L";", StringComparison::InvariantCultureIgnoreCase))
continue;
if (line->StartsWith(L"[", StringComparison::InvariantCultureIgnoreCase) && line->EndsWith(L"]", StringComparison::InvariantCultureIgnoreCase))
{
String^ sectionName = line->Substring(1, line->Length - 2);
if (String::IsNullOrWhiteSpace(sectionName))
continue;
currentSection = sectionName;
}
array<String^>^ parts = line->Split(gcnew array<wchar_t>(2) { '=' }, 2);
if (parts->Length == 1)
SetString(currentSection, parts[0]->Trim(), "");
else
SetString(currentSection, parts[0]->Trim(), parts[1]->Trim());
}
}
bool ContainsSection(String^ sectionName)
{
return _values->ContainsKey(sectionName);
}
bool ContainsValue(String^ sectionName, String^ valueName)
{
Dictionary<String^, String^>^ values = GetSection(sectionName);
if (values == nullptr)
return false;
return values->ContainsKey(valueName);
}
void Clear()
{
_values->Clear();
}
void SetString(String^ sectionName, String^ valueName, String^ value)
{
Dictionary<String^, String^>^ values = GetSection(sectionName);
if (values == nullptr)
{
values = gcnew Dictionary<String^, String^>(StringComparer::InvariantCultureIgnoreCase);
_values->Add(sectionName, values);
}
if (values->ContainsKey(valueName))
values[valueName] = value;
else
values->Add(valueName, value);
}
String^ GetString(String^ sectionName, String^ valueName, String^ defaultValue)
{
Dictionary<String^, String^>^ values = GetSection(sectionName);
if (values == nullptr)
return defaultValue;
if (values->ContainsKey(valueName))
return values[valueName];
return defaultValue;
}
private:
Dictionary<String^, Dictionary<String^, String^>^>^ _values;
Dictionary<String^, String^>^ GetSection(String^ sectionName)
{
if (_values->ContainsKey(sectionName))
return _values[sectionName];
return nullptr;
}
};
}
エラーチェックを追加する必要があり、不要なもの (セクションやコメントなど) を省略できます。さまざまな値の型を「読み取る」ために、結果を目的の値 (たとえば a )GetXYZ()
に解析するためのメソッドをさらに実装できます。GetString()
float
もう 1 つの解決策は、ネイティブ関数をインポートして INI を解析することです。彼らは非常にうまく機能します!