我正在尝试使用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
程序。另一方面,也许还有另一种更好的方法可以解决这个问题。你能提供任何建议吗?
提前致谢!
答案 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)
。