我有一个带有以下结构的字符串:
Student Name________AgeAddress_______________________Bithday___Lvl
示例:
Jonh Smith 016Some place in NY, USA 01/01/2014L01
如您所见,没有|
或,
另外,字段之间没有空间(如果您检查,年龄/地址和生日/级别之间就没有空间。
每个字段的大小都是静态的,因此,如果数据的长度较小,则它将包含白色空间。
我有一个需要填充这些信息的课程:
public class StudentData
{
public char[] _name = new char[20];
public string name;
public char[] _age = new char[3];
public string age;
public char[] _address = new char[30];
public string address;
public char[] _bday = new char[10];
public string bday;
public char[] _level = new char[3];
public string level;
}
有什么方法可以自动和动态?
我的意思是我真的不想这样编码:
myClass.name = stringLine.substring(0,19);
myClass.age = stringLine.substring(20,22);
那是因为我有更多的字段,该字段比此示例中添加的字段&使用其他不同数据的更多字符串线。
update :"史密斯"one_answers" 016"之间应该有很多空间,但是我不知道如何编辑。
update2 :如果我使用StringReader.Read(),我可以逃避使用子字符串和索引,但是它仍然不是那么动态,因为我需要为每个字段重复这3行。
StringReader reader = new StringReader(stringLine);
reader.Read(myClass._name, 0 myClass._name.Length);
myClass.name = new string(myClass._name);
鉴于您的要求,我提出了一个有趣的解决方案。所有这些都比说明的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
的属性,该属性采用两个参数。
-
OrderNumber
-
FixedLength
OrderNumber
参数表示字符串中的顺序(不是位置),而表示我们从字符串中处理的顺序。解析字符串时,第二个参数表示字符串的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; } }
}
现在属性很简单。接受我们在构造函数中讨论的eariler的两个参数。
最后,还有另一种方法可以将字符串解析到对象类型中,例如。
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
。然后列举该字典(由OrderNumber
订购),然后在输入字符串上两次调用SubString()
方法。
第一个子字符串是在第二个子字符串重置inputString
时解析下一个Token
以开始处理下一个令牌。
最后,由于它正在解析字符串,然后将解析的字符串应用于提供给方法的类Type
的属性。
现在可以像这样简单使用:
string data1 = "Jonh Smith 016Some place in NY, USA 01/01/2014L01";
StudentData student = FixedLengthFormatter.ParseString<StudentData>(data1);
这有什么作用:
- 以固定长度格式对属性属性进行解析。
这不做什么:
- 它确实将解析的字符串转换为另一种类型。因此,所有属性都必须是字符串。(可以通过在其中添加某种类型的铸造逻辑来轻松适应)。
- 它的测试不佳。这仅是针对几个样品进行测试的。
- 这绝不是那里的唯一或最好的解决方案。
您可以使用filehelpers库(nuget)。
只需使用属性来定义输入文件的结构:
[FixedLengthRecord]
public class StudentData
{
[FieldFixedLength(20)]
[FieldTrim(TrimMode.Right)]
public string name;
[FieldFixedLength(3)]
public string age;
[FieldFixedLength(30)]
[FieldTrim(TrimMode.Right)]
public string address;
[FieldFixedLength(10)]
public string bday;
[FieldFixedLength(3)]
public string level;
}
然后只需使用FileHelperEngine<T>
读取文件:
var engine = new FileHelperEngine<StudentData>();
var students = engine.ReadFile(filename);