带有paren分隔组的tcl regexp
我有一组字符串,看起来像:带有paren分隔组的tcl regexp,regex,tcl,match,Regex,Tcl,Match,我有一组字符串,看起来像: foo<xyz><123> bar pizza<oregano><tomato><mozzarella> 无论出于何种原因,都不会返回 你知道怎么解决这个问题吗 旁注 我试图解析的实际字符串使用方括号和圆括号作为分隔符。类似于:pizza[large](番茄)(橄榄)(奶酪),其中[term]可以出现0次或1次,而(term)s可以出现0次或更多次。 但由于方括号和圆括号的性质,这需要大量的引用,这可能太分
foo<xyz><123>
bar
pizza<oregano><tomato><mozzarella>
无论出于何种原因,
都不会返回
你知道怎么解决这个问题吗
旁注
我试图解析的实际字符串使用方括号和圆括号作为分隔符。类似于:pizza[large](番茄)(橄榄)(奶酪)
,其中[term]
可以出现0次或1次,而(term)
s可以出现0次或更多次。
但由于方括号和圆括号的性质,这需要大量的引用,这可能太分散注意力了,在这里不太有用)在这种情况下,诀窍是使用相当简单的重新处理和后处理结果:
% regexp -all -inline {^([^<>]+)((?:<[^<>]+>)*)$} foo<xyz><123>
foo<xyz><123> foo <xyz><123>
% regexp -all -inline {[^<>]+} <xyz><123>
xyz 123
%regexp-all-inline{^([^]+)((?:)*)$}foo
福福
%regexp-all-inline{[^]+}
xyz 123
您就快到了,但正在努力使用()*
,这将无法工作,因为它只捕获组匹配的一次。(我不知道它抓住了最后一场比赛,但因为我很少想要第一场或最后一场,而是全部,所以我使用了不同的方法。)
把这些放在一起,假设你有一个大的多行字符串,其中包含了你想查看的所有片段(例如,因为你从文件中读取了它),你会得到:
set str“foo
酒吧
比萨饼“
#找到匹配行并对其执行第一级提取
foreach{prefix attribs}[regexp-all-line-inline{^([^]+)((?:)*)$}$str]{
#拆分属性名称
设置属性[regexp-all-inline{[^]+}$attribs]
#证明我们真的匹配了他们
放置“prefix='$prefix',attributes=[join$attributes,]”
}
这将产生以下输出:
prefix='foo', attributes=xyz,123
prefix='bar', attributes=
prefix='pizza', attributes=oregano,tomato,mozzarella
前缀='foo',属性=xyz,123
前缀class='bar',属性=
前缀='pizza',属性=牛至、番茄、马苏里拉
让我们将其标记化
package require string::token
set lex {[[] LB []] RB [(] LP [)] RP [^][()]+ t}
set str {pizza[large](tomato)(olives)(cheese)}
% set tokens [::string::token text $lex $str]
{t 0 4} {LB 5 5} {t 6 10} {RB 11 11} {LP 12 12} {t 13 18} {RP 19" 19} {LP 20 20} {t 21 26} {RP 27 27} {LP 28 28} {t 29 34} {RP 35 35}
标记化后,我们可以用一种小语言将标记解析或评估为语句:
% set terms [lassign $tokens prefix]
proc t {str beg end} {
string range $str $beg $end
}
proc LB {str beg end} {
return "Optional term is: "
}
proc RB args {
return \n
}
proc LP {str beg end} {
rename LP {}
proc LP args {
return ", "
}
return "Arguments are: "
}
proc RP args {}
% puts "Prefix is: [eval [linsert $prefix 1 $str]]"
Prefix is: pizza
% % join [lmap term $terms {eval [linsert $term 1 $str]}] {}
Optional term is: large
Arguments are: tomato, olives, cheese
文件:
,
,
,
,
,
,
,
,
,
,
,
,
我可能误读了这些要求,但既然您已经在特殊符号中“编码”了所有结构细节,为什么不让Tcl列表机制来完成这项工作呢
set str {foo(xyz)(123)
bar
pizza[large](oregano)(tomato)(mozzarella)}
foreach line [split $str \n] {
set line [string map {"[" " " "]" " " ")(" " " "(" " {" ")" "} "} $line]
set suffix [lassign $line prefix]
lassign $suffix a b
if {[llength $suffix] == 2} {
set optional $a
set attributes $b
} else {
set optional ""
set attributes $a
}
puts "prefix='$prefix', optional='$optional', attributes='[join $attributes ,]'"
}
我很抱歉,严格地说,我的回答并没有解决regex的问题。而且比其他回复中的魔法要少;) 如果要将第二个捕获拆分为步骤2,则只需在第二个量化组周围使用捕获组-
“^([^]+)((?:)*)”
。使用内置格式工具时,请注意格式问题:经常在方括号前添加反斜杠。请参阅,使用{^([^]+)((?:)*)$}
regex,它是否工作得足够好?如果可以,我绝对建议将Tcl REs放在大括号中;它避免了所有反斜杠过多的问题(否则是复杂REs的主要问题),并且几乎所有REs都适合这种处理。@WiktorStribiżew perfect。因为你还没有发布答案,我接受了DonalFellows的答案,这个答案实际上是一样的。分几个步骤做事情通常比试图在一个巨大的单步中完成要简单得多,也不一定慢得多。(您没有使用的一点语法是非捕获括号,(?:…)
,这使得编写这类内容更加容易。)这是一个有时被称为文本润色的练习。显然,除了测试字符串映射
结果的列表属性或子列表的预期算术等之外,格式良好的检查是无法实现的。嗯,如果任何删除的单词包含空格怎么办?那你的话太多了。如果有一个不匹配的大括号怎么办?然后就是一个无效的列表。“单词包含空格”可以通过一个额外的(内部)水平的花括号来解决:{“[”“]”(“\}\{”(“\{\”)“\}\}”}
。这很好,就像在Tcl中一样,原子列表和单元素列表之间没有区别。“无效列表”可以被字符串捕获的是list
检查,这应该很好,因为要求处理的结果无论如何都应该是一个列表。这并不是说正则表达式或标记器不会更健壮,我在前面的评论中这样说。谢谢你的想法。但是,在我的情况下,我想要的是实际的字符串解析是“用户输入”,所以我不能真正依赖格式良好(尽管我在问题中没有这样说)
% set terms [lassign $tokens prefix]
proc t {str beg end} {
string range $str $beg $end
}
proc LB {str beg end} {
return "Optional term is: "
}
proc RB args {
return \n
}
proc LP {str beg end} {
rename LP {}
proc LP args {
return ", "
}
return "Arguments are: "
}
proc RP args {}
% puts "Prefix is: [eval [linsert $prefix 1 $str]]"
Prefix is: pizza
% % join [lmap term $terms {eval [linsert $term 1 $str]}] {}
Optional term is: large
Arguments are: tomato, olives, cheese
set str {foo(xyz)(123)
bar
pizza[large](oregano)(tomato)(mozzarella)}
foreach line [split $str \n] {
set line [string map {"[" " " "]" " " ")(" " " "(" " {" ")" "} "} $line]
set suffix [lassign $line prefix]
lassign $suffix a b
if {[llength $suffix] == 2} {
set optional $a
set attributes $b
} else {
set optional ""
set attributes $a
}
puts "prefix='$prefix', optional='$optional', attributes='[join $attributes ,]'"
}