使用正则表达式从收据中获取数据

时间:2012-12-11 23:28:27

标签: c# .net regex string split

我使用正则表达式从收据中获取每个订单项的数据。 收据将如下所示:

Qty Desc
1   JD *#
    MARTINI *#   
2   XXXXXX 
3   YYYYYY
4   JD
    PEPSI *#

所有商品都有数量和描述,其中一些商品还有额外的*#。另请注意,描述中可以包含空格,甚至多行,每行都可以拥有自己的 *#。我想要捕捉数量和描述(如果超过一行,得到所有行),我根本不关心额外的*#。所以在这个例子中,对于第一个行项目,我会捕获Quantity = 1和Description =“JD MARTINI”。对于第四个,Quantity = 4和Description =“JD PEPSI”。

我当前的正则表达式如下所示:

((\d+)\s+(.*)(\s+\*#)?)

它不起作用,我认为这是因为使最后一个括号可选允许贪婪的(.*)捕获绝对一切。如果最后一个括号不是可选的,那么正则表达式将为具有额外*#的订单项执行其工作,但它与第一​​个和第三个不匹配(因为它们没有额外的{ {1}})。

有什么想法吗?

3 个答案:

答案 0 :(得分:1)

在阅读修改过的问题之后,我已经确定你想要完成的任务不能用一个正则表达式完成。你必须做正则表达式匹配+替换的组合。 (见这个问题:Regular expression to skip character in capture group

匹配正则表达式:(\ d +)\ s +([A-Z \ s *#] * [A-Z] +)

替换正则表达式:(*#(\ s *))|(\ r \ n \ s +)(?= \ s)

匹配正则表达式将匹配数量和项目描述,包括任何中间换行符或*#次出现,从而省略最终的*#。我假设描述中的最后一个字符是一封信。

运行匹配正则表达式后,您将获得一个匹配数组,您将需要迭代以转换为对象。我写了一些方便的代码来为你做这件事。对于每个对象,您将在对象的描述上运行替换正则表达式,这将删除无关的空格和*#。

     class ReceiptItem
    {
        public int Quantity { get; set; }
        public string Description { get; set; }

        public override string ToString()
        {
            return string.Format("{0}\t{1}", Quantity, Description);
        }
    }

    private void button1_Click(object sender, EventArgs e)
    {
        var matches = Regex.Matches(textBox1.Text, @"(\d+)\s+([A-Z\s\*\#]*[A-Z]+)", RegexOptions.Multiline);
        var items = (from Match m in matches
                     select new ReceiptItem()
                                {
                                    Quantity = int.Parse(m.Groups[1].Value),
                                    Description = Regex.Replace(m.Groups[2].Value, @"(\*\#(\s*))|(\r\n\s+)(?=\s)", "")
                                });

        listBox1.Items.AddRange(items.ToArray());
    }

答案 1 :(得分:0)

尝试使用此正则表达式(使用Multiline选项):

(\d+)\s+(?:(.*)(?:\s+\*#)|([^#]*))$

答案 2 :(得分:0)

试一试。我认为它可以满足您的需求。

((\d+)\s+(.+?)(\s+\*#)*)