TXR:如何组合以下行开头的所有行?

时间:2017-01-22 20:14:23

标签: text-processing

我正在尝试使用txr解析shell命令的文本输出。

文本输出使用其后面的标签缩进行来继续当前行(不是文字\t字符,如下所示)。请注意,在其他变量赋值行(不表示扩展长度值)上,输入中有前导空格。

Variable Group: 1
 variable = the value of the variable
 long_variable = the value of the long variable
\tspans across multiple lines
 really_long_variable = this variable extends
\tacross more than two lines, but it
\tis unclear how many lines it will end up extending
\tacross ahead of time

Variable Group: 2
 variable = the value of the variable in group 2
 long_variable = this variable might not be that long
 really_long_variable = neither might this one!

我如何使用txr模式语言捕获这些?我知道@(freeform)指令和它的可选数字参数,将下一个n行视为一个大行。因此,在我看来,正确的方法将是:

@(collect)
Variable Group: @i
 variable = @value
@(freeform 2)
 long_variable = @long_value
@(set long_value @(regsub #/[\t ]+/ "" long_value))
@(freeform (count-next-lines-starting-with-tab))
 really_long_variable = @really_long_value
@(set really_long_value @(regsub #/[\t ]+/ "" really_long_value))
@(end)

但是,我不清楚如何用TXR lisp编写count-next-lines-starting-with-tab程序。另一方面,也许还有另一种更好的方法可以解决这个问题。你能提供任何建议吗?

提前致谢!

1 个答案:

答案 0 :(得分:1)

让我们应用KISS原则;我们不需要引入@(freeform)。相反,我们可以分别捕获(可能)多行变量的主线和延续线。然后,智能地将它们与@(merge)

组合在一起
@(collect)
Variable Group: @i
 variable = @value
 long_variable = @l_head
@  (collect :gap 0 :vars (l_cont))
        @l_cont
@  (end)
 really_long_variable = @rl_head
@  (collect :gap 0 :vars (rl_cont))
        @rl_cont
@  (end)
@  (merge long_variable l_head l_cont)
@  (merge really_long_variable rl_head rl_cont)
@(end)

请注意,上面的大缩进应该是文字标签。我们可以使用@\t编码标签而不是文字标签。

对实际数据进行测试,\t替换为标签:

$ txr -Bl new.txr data
(i "1" "2")
(value "the value of the variable" "the value of the variable in group 2")
(l_head "the value of the long variable" "this variable might not be that long")(l_cont ("spans across multiple lines") nil)
(rl_head "this variable extends" "neither might this one!")
(rl_cont ("across more than two lines, but it" "is unclear how many lines it will end up extending"
          "across ahead of time") nil)
(long_variable ("the value of the long variable" "spans across multiple lines")
 ("this variable might not be that long"))
(really_long_variable ("this variable extends" "across more than two lines, but it"
                       "is unclear how many lines it will end up extending" "across ahead of time")
 ("neither might this one!"))

我们对连续行使用严格的collect:vars,这样即使没有收集任何内容,变量也会绑定到nil:gap 0阻止这些内部收集扫描不以标签开头的行:另一种严格措施。

@(merge)有"特别"用于组合具有不同嵌套级别的字符串列表的语义;它非常适合收集不同级别的数据,基本上是为这种东西量身定做的。此问题与提取HTTP,Usenet或电子邮件标头非常相似,后者可以有连续行。

关于如何编写Lisp函数以展望数据的主题,最重要的方面是如何处理当前位置的数据。 TXR模式匹配通过回溯一个惰性字符串列表(行/记录)来工作。我们可以使用@(data)指令捕获给定输入位置的列表指针。然后我们可以将其视为列表:

@(data here)
@(bind tab-start-lines @(length (take-while (f^ #/\t/) here))

现在tab-start-lines计算输入中有多少行以制表符开头。但是,遗憾的是,take-while有终止条件错误;如果以下数据只包含一条或多条tab行,则表示行为异常。在TXR 166发布之前,这需要一些解决方法:(take-while [iff stringp (f^ #/\t/)] here)