【问题标题】:Regex to capture colon-separated key-value pairs, with multi-line values正则表达式捕获以冒号分隔的键值对,具有多行值
【发布时间】:2012-06-20 18:41:00
【问题描述】:

我目前正在使用 Ruby on Rails(在 Eclipse 中)开发一个项目,我的任务是使用正则表达式将数据块拆分为相关部分。

我决定根据 3 个参数分解数据:

  1. 该行必须以大写字母开头(RegEx 等效 - /^[A-Z]/
  2. 它必须以 : 结尾(RegEx 等效项 - /$":"/

如果有任何帮助,我将不胜感激......我在控制器中使用的代码是:

@f = File.open("report.rtf")  
@fread = @f.read  
@chunk = @fread.split(/\n/)

其中@chunk 是将由拆分创建的数组,@fread 是正在拆分的数据(通过新行)。

任何帮助将不胜感激,非常感谢!

我无法发布确切的数据,但基本上是这样(这与医学有关)

考试 1:CBW 8080

结果:

此报告由特定度量决定。 请参阅原始报告。

比较:2012 年 1 月 30 日、2012 年 3 月 8 日、2012 年 4 月 9 日

RECIST 1.1: 哈哈哈哈哈哈

理想的输出是一个数组:

["Exam 1:", "CBW 8080", "RESULT", "This report is dictated with specific measurement. Please see the original report.", "COMPARISON:", "1/30/2012, 3/8/12, 4/9/12", "RECIST 1.1:", "BLAH BLAH BLAH"]

PS 我只是使用 \n 作为占位符,直到我让它工作

【问题讨论】:

  • 数据是否来自文件?为什么不使用 readlines 而不是在换行符上手动拆分?
  • 我们需要更多信息。一行中间可以有冒号吗?一行是以冒号结尾还是冒号后面还有换行符?线不匹配怎么办?重音/外国大写字母呢? Eclipse 在这里的相关性是什么?
  • 你要提取哪些“相关部分”?
  • 你没有指定你想要的输出。
  • 我在原始问题中回答了您的所有疑问...Eclipse 无关紧要...非常感谢您的帮助!

标签: ruby-on-rails ruby regex eclipse


【解决方案1】:

我不完全确定您在寻找什么。如果您希望所有出现的大写字母后跟一些文本和分号,那么您可以这样做:

str.scan(/[A-Z].*?:/)

【讨论】:

  • 这是目前最好的答案,我只需要输出其他行
【解决方案2】:

应该这样做。

/^[A-Z].*:$/

【讨论】:

  • 这只是返回整个文件的一个大数组,没有任何拆分:/
  • 抱歉,我以为您的意思是您已经将其拆分为 \n 并且您将通过另一个正则表达式运行每一行——我的解决方案旨在匹配每一行。
  • 如果我拆分每一行,然后在每一行上尝试,会产生所需的输出吗?
  • 哦,不,不会的。我刚刚用您的新示例查看了您更新的问题。在您最初的问题中,不清楚有时“价值”会在同一行,而其他时候会在不同的行上。我将发布一个新的解决方案,以免混淆这个讨论。
【解决方案3】:

正则表达式可以是:/(^[A-Z].*\:)/m 然后通过添加来提取:

@chunk = @fread.scan(/(^[A-Z].*\:)/m)

如果@fread 是一个字符串。您可以使用http://rubular.com/ 在 ruby​​ 中测试正则表达式。

【讨论】:

  • 这会返回一个空数组:/
  • 那么你需要 /(^[A-Z].*\:$)/m ,它正在扫描多行。
  • 尝试打开您的终端并运行 irb,以获取交互式 ruby​​。您可以在某些字符串上尝试该正则表达式。我不确定您的输入格式。
【解决方案4】:

鉴于已澄清的问题,这是一个新的解决方案。

更新

首先将整个数据块(包括换行符和所有)“Slurp”成一个字符串。

str = IO.read("report.rtf")

然后使用这个正则表达式:

captures = str.scan(/(?<=^|[\r\n])([A-Z][^:]*):([^\r\n]*(?:[\r\n]+(?![A-Z].*:).*)*)/)

在此处查看实时示例:http://rubular.com/r/8w3X6WGq4l

答案,解释:

    (?<=                Lookbehind assertion.
        ^                   Start at the beginning of the string,
        |                   or,
        [\r\n]              a new line.
    )
    (                   Capture group 1, the "key".
        [A-Z][^:]*          Capital letter followed as many non-colon
                            characters as possible.
    )
    :                   The colon character.

    (                   Capture group 2, the "value".
        [^\r\n]*            All characters (i.e. non-newline characters) on the
                            same line belongs to the "value," so take them all.

        (?:             Non-capture group.

            [\r\n]+         Having already taken everything up to a newline
                            character, take the newline character(s) now.

            (?!             Negative lookahead assertion.
                [^A-Z].*:       If this next line contains a capital letter,
                                followed by a string of anything then a colon,
                                then it is a new key/value pair, so we do not
                                want to match this case.
            )
            .*              Providing this isn't the case though, take the line!

        )*              And keep taking lines as long as we don't find a
                        key/value pair.
    )

【讨论】:

  • 太棒了,它完美地完成了这项工作,你向 T 解释了它。非常感谢!现在我只需要解决“UTF-8 中的无效字节序列”错误就可以了!
  • 顺便说一句,您知道如何摆脱该错误吗?我认为这与编码有关:/
  • 不知道,但你见过这个:stackoverflow.com/questions/2982677/…?
  • 如果有人感兴趣,答案是 str = IO.read("report_test").force_encoding("ISO-8859-1").encode("utf-8", replace: nil)非常感谢@acheong87!
【解决方案5】:

另一个解决方案:

input_str.split("\r\n").each |s| do
    var_name = s.split(": ")[0]
    var_value = s.split(": ")[1]
    # do whatever you like
done

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-07-19
    • 2022-01-21
    • 1970-01-01
    • 1970-01-01
    • 2012-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多