あなたの要件を考慮して、興味深い解決策を思いつきました。String.SubString()
いずれにせよ、前述の方法を使用するよりも複雑で時間がかかる可能性があります。
ただし、この解決策は他の型や他の文字列にも適用できます。Attributes
、Properties
、の概念を使用しReflection
て、固定長で文字列を解析し、クラスのプロパティを設定しました。
StudentData
より従来のコーディングスタイルに従うようにクラスを変更したことに注意してください。MSDN のこの便利なガイドに従ってください: http://msdn.microsoft.com/en-us/library/xzf533w0(v=vs.71).aspx
こちらが新しいStudentData
クラスです。フィールドではなくプロパティを使用することに注意してください。(ここでは説明しません)。
public class StudentData
{
string name;
string age;
string address;
string bday;
string level;
[FixedLengthDelimeter(0, 20)]
public string Name { get { return this.name; } set { this.name = value; } }
[FixedLengthDelimeter(1, 3)]
public string Age { get { return this.age; } set { this.age = value; } }
[FixedLengthDelimeter(2, 30)]
public string Address { get { return this.address; } set { this.address = value; } }
[FixedLengthDelimeter(3, 10)]
public string BDay { get { return this.bday; } set { this.bday = value; } }
[FixedLengthDelimeter(4, 3)]
public string Level { get { return this.level; } set { this.level = value; } }
}
各プロパティには、FixedLengthDelimeter
2 つのパラメーターを受け取る Attribute という名前があることに注意してください。
OrderNumber
FixedLength
パラメータは、文字列内のOrderNumber
順序 (位置ではなく) を示しますが、文字列から処理する順序を示します。2 番目のパラメーターはLength
、文字列を解析するときの文字列の を示します。これが完全な属性クラスです。
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public sealed class FixedLengthDelimeterAttribute : Attribute
{
public FixedLengthDelimeterAttribute(int orderNumber, int fixedLength)
{
this.fixedLength = fixedLength;
this.orderNumber = orderNumber;
}
readonly int fixedLength;
readonly int orderNumber;
public int FixedLength { get { return this.fixedLength; } }
public int OrderNumber { get { return this.orderNumber; } }
}
これで、属性は十分に単純になりました。コンストラクターで前に説明した 2 つのパラメーターを受け入れます。
最後に、文字列を次のようなオブジェクト タイプに解析する別の方法があります。
public static class FixedLengthFormatter
{
public static T ParseString<T>(string inputString)
{
Type tType = typeof(T);
var properties = tType.GetProperties(BindingFlags.Instance | BindingFlags.Public); //;.Where(x => x.GetCustomAttributes(typeof(FixedLengthDelimeterAttribute), false).Count() > 0);
T newT = (T)Activator.CreateInstance(tType);
Dictionary<PropertyInfo, FixedLengthDelimeterAttribute> dictionary = new Dictionary<PropertyInfo, FixedLengthDelimeterAttribute>();
foreach (var property in properties)
{
var atts = property.GetCustomAttributes(typeof(FixedLengthDelimeterAttribute), false);
if (atts.Length == 0)
continue;
dictionary[property] = atts[0] as FixedLengthDelimeterAttribute;
}
foreach (var kvp in dictionary.OrderBy(x => x.Value.OrderNumber))
{
int length = kvp.Value.FixedLength;
if (inputString.Length < length)
throw new Exception("error on attribute order number:" + kvp.Value.OrderNumber + " the string is too short.");
string piece = inputString.Substring(0, length);
inputString = inputString.Substring(length);
kvp.Key.SetValue(newT, piece.Trim(), null);
}
return newT;
}
}
上記のメソッドは、文字列の解析を行うものです。これは、FixedLengthDelimeter
属性が適用されたすべてのプロパティを読み取る非常に基本的なユーティリティですDictionary
。次に、そのディクショナリが列挙され ( の順序で) 、入力文字列に対してメソッドが 2 回OrderNumber
呼び出されます。SubString()
最初の部分文字列は次のトークンを解析し、2 番目の部分文字列は次のトークンの処理を開始するためにToken
リセットします。inputString
最後に、文字列を解析するときに、解析された文字列をType
メソッドに提供されたクラスのプロパティに適用します。
これは次のように簡単に使用できます。
string data1 = "Jonh Smith 016Some place in NY, USA 01/01/2014L01";
StudentData student = FixedLengthFormatter.ParseString<StudentData>(data1);
これが何をするか:
- 固定長形式のプロパティ属性に対して文字列を解析します。
これがしないこと:
- 解析された文字列を別の型に変換します。したがって、すべてのプロパティは文字列でなければなりません。(これは、いくつかのタイプキャストロジックを追加することで簡単に適応できます)。
- 十分にテストされていません。これは、いくつかのサンプルに対してのみテストされています。
- それが唯一の、または最善の解決策であるとは限りません。