【问题标题】:Ruby regex to match a four item lineRuby 正则表达式匹配四项行
【发布时间】:2013-01-06 01:47:30
【问题描述】:

我正在使用 pdf-reader 阅读我的每月财务记录。我感兴趣的所有行都以描述开头,然后是日期##/##/####,然后是两美元的金额 $#.## $#.##。

像这样:

Gas Station            12/12/2012         $68.00             $485.00

有时这些数字会有括号 $(4.50) 表示退货或负数。我希望所有符合此“模式”的行都作为每行 4 项列表返回。因此,我将整条线与不确定数量的空格相匹配,偶尔还会在价格上加上括号。

require 'pdf-reader'
reader = PDF.Reader.new("month.pdf")
reader.pages.each do |page|
  page.split("\n").each do |line|
  if line # MATCHING REGEX HERE
     #HANDLE 4 VALUES FROM REGEX
  end
end

对于任何想了解我如何使用代码的人来说,这里是源代码https://github.com/danielpclark/INGdirect_pdf_processor。随意在您自己的项目中使用它来处理银行数据。

【问题讨论】:

  • 您尝试过任何正则表达式吗?什么有效?什么没有?
  • 你为什么还要使用正则表达式?如果所有内容都在列中,为什么不在空白处拆分行? *.com/questions/13537920/ruby-split-by-whitespace
  • (.*)\s+(\d{2}\/\d{2}\/\d{4})\s*(\(?\$.\d+\.\d+\)?)\s+(\(?\$.\d+\.\d+\)?) 这对我有用。 PDF 有很多其他垃圾数据,例如银行图像、大量信息和其他一些分类数据。所以空白分割对我不起作用。
  • 我插入了来自@Andrea Singh 的模式,并使用了来自@the Tin Man pattern=Regexp.new('(.*)\s+(\d{2}\/\d{2}\/\d{4})\s*(\(?\$.\d+\.\d+\)?)\s+(\(?\$.\d+\.\d+\)?)') line.scan(pattern) 的扫描建议,这在一个可用的列表/数组中给了我想要的输出。

标签: ruby regex


【解决方案1】:

试试这个正则表达式:

(.*)\s+(\d{2}\/\d{2}\/\d{4})\s*(\(?\$\d+\.\d+\)?)\s+(\(?\$\d+\.\d+\)?)

它将有 4 个匹配项:

  • 说明
  • 日期
  • 第一笔金额
  • 秒数

这里是 Rubular:http://rubular.com/r/2mcrGZiAOe

您也可以使用命名匹配,因为它们更优雅一些(也是多行正则表达式的 x 修饰符):

if line_match = line.match(/
    (?<description>.*)\s+
    (?<date>\d{2}\/\d{2}\/\d{4})\s*
    (?<amount_1>\(\$\d+\.\d+\)|\$\d+\.\d+)\s+
    (?<amount_2>\(\$\d+\.\d+\)|\$\d+\.\d+)/x)
  # now you can use: line_match[:date], line_match[:amount_1], etc.

【讨论】:

  • 注意:这匹配 $ 之前的金额周围的括号,而不是它之后。如果这对 OP 很重要,这不会强制匹配括号。
  • 是的,它们是可选的,尽管它们后面有问号:\(?\)?
  • 两个小调整,你的正则表达式将处理 $(xx.xx) 格式,甚至强制匹配括号:(.*)\s+(\d{2}\/\d{2}\/\d{4})\s*(\$\(\d+\.\d+\)|\$\d+\.\d+)\s+(\$\(\d+\.\d+\)|\$\d+\.\d+)
  • 这成功了。我必须在每个美元符号后添加一个句点,然后一切正常。 (.*)\s+(\d{2}\/\d{2}\/\d{4})\s*(\(?\$.\d+\.\d+\)?)\s+(\(?\$.\d+\.\d+\)?) 美元符号后面的句点允许所有括号。
【解决方案2】:

String.scan 是一个很好的方法来获取这样的数据:

string = 'This is some text
Gas Station   12/12/2012 $68.00   $485.00
This some more text
Reimbursement 01/01/2012 $(68.00) $(485.00)
'

string.scan(%r{^(.+?) \s+ (\d{1,2}/\d{1,2}/\d{4}) \s+ ([$()\d.]+) \s+ ([$()\d.]+) }x)
[
    [0] [
        [0] "Gas Station",
        [1] "12/12/2012",
        [2] "$68.00",
        [3] "$485.00"
    ],
    [1] [
        [0] "Reimbursement",
        [1] "01/01/2012",
        [2] "$(68.00)",
        [3] "$(485.00)"
    ]
]

【讨论】:

  • 这很好!非常感谢!
最近更新 更多