2013-10-25 84 views
0

我想用几十个条目解析文本文件。现在,我有一个简单化向下的解决方案,通过逐行地读取并比较了对硬编码字符串:C#解析文本文件 - 按索引访问类字段

while ((line = reader.ReadLine()) != null) //returns null if end of stream 
{ 
    cmpStr = "MODE"; 
    try 
    { 
     if (line.Equals(cmpStr))       
      GlobalData.mode = Convert.ToInt32(line.Remove(0, cmpStr.Length)); 
    } 
    catch { } 

    cmpStr = "TIME_YEAR"; 
    try 
    { 
     if (line.Equals(cmpStr))       
      GlobalData.time_year = Convert.ToInt32(line.Remove(0, cmpStr.Length)); 
    } 
    catch { } 


    // ... repeat to parse the remaining lines 
} 

全球国际会议是一个静态类,看起来像这样:

public static class GlobalData 
{ 

    public static int mode;     
    public static int time_year; 
    public static int time_month; 
    public static int time_day; 
    public static int time_hour; 
    public static int time_minute; 
    // other entries omitted 

    public static string[] GlobalKeywords = new string[37] 
    { 
     "MODE", 
     "TIME_YEAR", 
     "TIME_MONTH", 
     "TIME_DAY", 
     "TIME_HOUR", 
     "TIME_MINUTE", 
     // other entries omitted  
    }; 
} 

如果它是可以通过指数访问我的静态字段,我会做:

int i = 0; 
while ((line = reader.ReadLine()) != null) 
{ 
    cmpStr = GlobalData.GlobalKeywords[i]; // when i == 0: cmpStr = "MODE" 

    if (line.Equals(cmpStr)) 
     GlobalData[i] = Convert.ToInt32(line.Remove(0, cmpStr.Length)); 
     // GlobalData[0] would be GlobalData.mode, and so on (but doesn't work) 

    i++; 
} 
catch { } 

所以,尽管我可以设置一个循环来比较关键字字符串数组, 我该如何分配我的静态类的某个字段?

BR 克里斯

+0

我不知道做GlobalData [i]如何成为GlobalData.mode。 – srsyogesh

+0

你能举一个关于如何格式化你的输入文件的例子吗? – Steve

+0

你是对的,那是失踪。它是一个.txt文件,其中每个条目位于一行中,并且行由CR + LF(Windows换行符)分隔。例如,该文件可能如下所示:MODE 5 TIME_YEAR 2013 TIME_MONTH 10 等 – user2286339

回答

1

我不知道你的业务限制是什么,所以很难提出一个很简单的解决方案,但有几点:

cmpStr = "MODE"; 
try 
{ 
    if (line.Equals(cmpStr))       
     GlobalData.mode = Convert.ToInt32(line.Remove(0, cmpStr.Length)); 
} 

这将无法正常工作就像你(可能预期的那样) - 如果line.Equals("MODE")那么line.Remove(0, "MODE".Length)是一个空字符串。你可能想要的是line.StartsWith(cmpStr)line.Contains(cmpStr)

全球国际会议是一个静态类

这似乎不是一个好方法,你在做什么。您可能需要阅读静态类和何时使用它们(MSDN是一个很好的起点,但它显然不能涵盖所有内容:http://msdn.microsoft.com/en-us/library/79b3xss3%28v=vs.80%29.aspx)。

除此之外,你也许可以简单地用字典替换所有int字段(不过请重新考虑静态的方法如上文所述):

public static Dictionary<String, int> Items = new Dictionary<String, int>(); 

然后你解析代码看起来是这样的:

while ((line = reader.ReadLine()) != null) //returns null if end of stream 
{ 
    var matchingString 
     = GlobalData.GlobalKeywords.FirstOrDefault(s => line.StartsWith(s)); 
    if (matchingString != null) 
     GlobalData[matchingString] 
      = Convert.ToInt32(line.Remove(0, matchingString.Length)); 
} 

然后,您将能够使用例如GlobalData.Items["MODE"]

最后一个位:您可以考虑在您的全局数据类引入的常数值,例如:

public const String MODE = "MODE"; 

然后你可以使用GlobalData.Items[GlobalData.MODE],避免错别字:写GlobalData.Items[GlobalData.MODe]会导致编译错误。

1

替换此:

public static int mode;     
public static int time_year; 
public static int time_month; 
public static int time_day; 
public static int time_hour; 
public static int time_minute; 

有了这个:

public static Dictionary<string, int> my_values = new Dictionary<string, int>(); 

然后更换:

GlobalData[i] = Convert.ToInt32(line.Remove(0, cmpStr.Length)); 

有:

GlobalData.my_values[cmpStr] = Convert.ToInt32(line.Remove(0, cmpStr.Length)); 

即使我不明白您希望Convert.ToInt32的工作方式如何,您应该按照您的要求做。你调用Remove的方式会创建一个空字符串(可能转换为0,我不记得),即使没有,行也不包含一个数字,因为你成功地将它与一个字符串比如“模式”。

1

一个简单的(而不是真正干净的)方法是将indexer添加到您的全局数据类,并根据索引决定设置哪个字段。但是你必须在每次添加一个字段时扩展索引器(基本上你将if/switch从while循环移到索引器中)。
如果您可以将关键字与字段名称相匹配,您也可以使用反射。这不是非常高效,但只要您可以将关键字映射到新字段名称就不需要进行扩展。
另一种方法是创建一个字典>。在本词典中,您注册了关键字,例如(伪代码): 类级别变量:

private keywordsDict = new Dictionary<string, Action<int>>(); 

在构造函数中:

keywordsDict.Add("MODE", delegate(value) GlobalData.mode = value); 

在while循环:

var action = keywordsDict[line]; 
action(value); 

在后一种方法,你只需要如果您有新的关键字/字段,则扩展字典但不包含算法。

1

一个解决问题的优雅方法是为每个可接受的字符串准备不同的操作。您使用的是Dictionary(Of String, <Action>),其中Action是一种常见的委托类型,它在输入中接收字符串并知道如何根据行首的关键字处理它。

// The common signature for every methods stored in the value part of the dictionary 
public delegate void ParseLine(string line); 

// Global dictionary where you store the strings as keyword 
// and the ParseLine as the delegate to execute 
Dictionary<String, ParseLine> m_Actions = new Dictionary<String, ParseLine>() ; 

void Main() 
{ 
    // Initialize the dictionary with the delegate corresponding to the strings keys 
    m_Actions.Add("MODE", new ParseLine(Task1)); 
    m_Actions.Add("TIME_YEAR", new ParseLine(Task2)); 
    m_Actions.Add("TIME_MONTH", new ParseLine(Task3)); 
    m_Actions.Add("TIME_DAY", new ParseLine(Task4)); 
    ..... 

    while ((line = reader.ReadLine()) != null) 
    { 
     // Search the space that divide the keyword from the value on the same line 
     string command = line.Substring(0, line.IndexOf(' ')).Trim(); 
     // a bit of error checking here is required 
     if(m_Actions.ContainsKey(command)) 
      m_Actions[command](line); 

    } 
} 

void Task1(string line) 
{ 
    // this will handle the MODE line 
    GlobalData.Mode = Convert.ToInt32(line.Substring(line.IndexOf(' ')+1).Trim()); 

} 
void Task2(string line) 
{ 
    GlobalData.time_year = Convert.ToInt32(line.Substring(line.IndexOf(' ')+1).Trim()); 
} 
void Task3(string line) 
{ 
    ..... 
} 
void Task4(string line) 
{ 
    ..... 
} 
0

可能我可以告诉你如何在C#中实现它(GlobalData [i])认为它不是你正在寻找的答案。

class GlobalData 
    { 
     private string[] array = new string[10]; 
     public GlobalData() 
     { 
      //now initialize array 
      array[0] = "SomeThingA"; 
      array[1] = "SomeThingB";//continue initialization. 
     } 
     public string this[int index] 
     { 
      get {return array[index];} 
     } 
    } 

现在,客户端可以使用像全球国际,

GlobalData gd = new GlobalData(); 
    gd[1] = "SomeOtherThing" ; //set the value. 
    string value = gd[1];//get the value 

但这不能通过使类的静态,你看到它的工作原理与“这个”