65.9K
CodeProject 正在变化。 阅读更多。
Home

使用正则表达式支持灵活的文本格式

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2投票s)

2009年6月30日

CPOL

2分钟阅读

viewsIcon

23968

downloadIcon

218

正则表达式使您的应用程序能够解析自定义格式的文本文件。

flexformat.jpg

引言

我正在编写一个小型的数据库应用程序,允许用户将纯文本文件中的记录导入到Access数据库中。我遇到的一个问题是,不同的用户会有不同的格式:有些是制表符分隔的,有些是逗号分隔的;有些具有固定宽度的字段,而有些则没有。您可以使用switch语句来处理它们,但是当格式的数量增加时,代码的丑陋程度也会增加。更困难的是,通常在编码时您并不知道格式是什么。

因此,我需要支持自定义格式;它必须足够灵活,并且应用程序可以轻松理解。这看起来是一项艰巨的任务,直到我接触到正则表达式的概念。

Using the Code

它非常简单易用,因为它除了使用正则表达式的想法之外,几乎没有其他内容。演示项目包含在formats.xml中描述的两种格式,以及两个示例输入文件。您需要

  1. flex_format.cs添加到您的项目中。
  2. 在初始化期间加载存储在XML文件中的格式信息。
  3. //Read Formats Supported
    XmlSerializer s = new XmlSerializer(typeof(ArrayList), 
                          new Type[] { typeof(flex_format) });
    TextReader r = new StreamReader("formats.xml");
    formats_supported = (ArrayList)s.Deserialize(r);
    r.Close();
  4. 当用户打开OpenFileDialog时,将格式信息填充到文件过滤器中。
  5. OpenFileDialog dlg = new OpenFileDialog();
    //Stuff the dialog's file filter with formats supported
    foreach (flex_format format in formats_supported)
    {
      dlg.Filter += (dlg.Filter.Length>0?"|":"")+ 
          format.description + "|*" + format.suffix;
    }
    if (dlg.ShowDialog() == DialogResult.OK)
    {
      load_list(dlg.FileName);
    }
  6. 使用格式描述中指定的正则表达式解析文本文件。
  7. private void load_list(string file_name)
    {
      flex_format format = null;
      //Determine the file format by file name suffix
      foreach (flex_format fmt in formats_supported)
      {
        if (file_name.EndsWith(fmt.suffix))
        {
          format = fmt;
          break;
        }
      }
      
      listView1.Clear();
      //Stuff the listview columns with field names
      foreach(string field_name in format.entries)
      {
        listView1.Columns.Add(field_name);
      }
    
      //Now read the content of the input file 
      textBox1.Text = null; 
      StreamReader reader = new StreamReader(file_name);
      while (true)
      {
        string line = reader.ReadLine();
        textBox1.Text += line+"\r\n";
        if(line == null || line.Length == 0) break;
    
    
        //This is where the regular expression is used
        Match match = new Regex(format.pattern).Match(line);
        if(!match.Success) continue;
        ListViewItem item = new ListViewItem(match.Groups[1].Value);
        for (int i = 2; i < match.Groups.Count; i++)
        {
           item.SubItems.Add(match.Groups[i].Value);
        }
        listView1.Items.Add(item);
      } 
    }
  8. 要添加新格式,您可以手动编辑XML文件,也可以以编程方式使用XML序列化。这是演示项目中使用的XML文件的一部分。此格式允许用户使用不同的速度单位,如果没有正则表达式的帮助,这将更难实现。
  9. <anyType xsi:type="flex_format" 
       description="Car Speed Record Database" 
       suffix=".spd" 
       pattern="([^\t]+)\t([^\t]+)\t([\d\.]+)\s*(mph|km/h|m/s)">
    <entries>
    <entry>Make</entry>
    <entry>Model</entry>
    <entry>TopSpeed</entry>
    <entry>Unit</entry>
    </entries>
    </anyType>

为什么使用正则表达式

flex_format将描述、文件后缀、正则表达式模式和字段名称数组存储在XML文件中。文件格式可以灵活到什么程度?就像正则表达式一样灵活。结合XML序列化,您将获得一个简洁的解决方案来支持灵活的文本格式。更重要的是,您可以在不更改应用程序的情况下轻松添加对新格式的支持。

修订历史

  • [2009年7月2日] 对演示项目进行了小的更改。
  • [2009年6月20日] 初始版本。
访问我在C#和数字成像方面的博客,如果您能阅读中文:)
© . All rights reserved.