【问题标题】:TCL regexp not returning expected matchesTCL 正则表达式未返回预期匹配
【发布时间】:2018-05-09 18:25:26
【问题描述】:

我正在从文件名中提取电压的数值数据。该名称包含三个这样的数据,但正则表达式只返回 2。

set data "blabla_0p500v_0p530v_0p550v_m25c_foo.dat"
regexp -all -inline {_(\dp\d{3})v_} $data

返回:

_0p500v_ 0p500 _0p550v_ 0p550

我期待:

_0p500v_ 0p500 _0p530v_ 0p530 _0p550v_ 0p550

不确定缺少什么。

感谢您的帮助。

【问题讨论】:

  • 看来你可以使用regexp -all -inline {\dp\d{3}} $data直接获取匹配项。
  • @PeterLewerin 然后,不知道匹配是否发生在下划线之间(除非您为此添加一些代码)。
  • @WiktorStribiżew:显然。而且,从这个例子来看,这似乎并不重要。

标签: regex tcl


【解决方案1】:

使用积极的前瞻:

_(\dp\d{3})v(?=_)

这种方式后面的下划线不会被消耗,并准备好被下一次迭代匹配。

在匹配部分附加_

set output [regexp -all -inline {_(\dp\d{3})v(?=_)} $data]
set index 0
foreach item $output {
  puts [expr {$index % 2 == 0 ? "$item\_": $item}]
  incr index
}

Live demo

【讨论】:

  • 我最喜欢这个。我不需要捕获中的“v_”,但希望将其作为模式的一部分。
【解决方案2】:

您可以使用您的模式,但遍历字符串以搜索第一个字符 _ 的所有出现(请注意,如果第一个字符不是“硬编码”,则可以使用 -indices 选项通过正则表达式完成,但在这里您可以仅使用string first),并在每个位置检查正则表达式匹配。如果找到匹配项,lappend 将匹配项和第一个捕获到列表中。

Tcl code demo

set data "blabla_0p500v_0p530v_0p550v_m25c_foo.dat"
set RE {_(\dp\d{3}v)_}
set result []
set idx [string first "_" $data 0]
while {$idx > -1} {
    if {[regexp -start $idx $RE $data whole between]==1} {
        lappend result $whole $between
    }
    set idx [string first "_" $data $idx+1]
}
puts $result

输出:

_0p500v_ 0p500v _0p530v_ 0p530v _0p550v_ 0p550v

请注意,您可以使用@revo's approach,但您必须通过检查结果列表中的所有项目并将_ 附加到以_ 开头的项目来重构输出:

set data "blabla_0p500v_0p530v_0p550v_m25c_foo.dat"
set RE {_(\dp\d{3}v)(?=_)}
set ms [regexp -all -inline $RE $data]
set result []
foreach m $ms {
    if {[string index $m 0] == "_"} {
        lappend result "${m}_"
    } else {
        lappend result $m
    }
}
puts $result

another Tcl demo online

只是为了澄清这里的“不消耗”是什么意思:(?=_),一种非消耗模式,不会将 _ 放入正则表达式匹配值中,并且正则表达式索引保持在 _ 之前,当执行前瞻模式。因此,下一场比赛可以在这个_之前开始。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-02-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多