正则表达式在tcl中的怪癖

时间:2017-12-27 16:27:48

标签: regex tcl

这个问题是关于理解Vivado内置的TCL 8.5中特定正则表达式的行为,特别是or - 两个正则表达式部分一起得到了意想不到的结果:

我致力于使用正则表达式缩进命令行的文本块。我的第一个想法是将每个newline替换为newline 一些spaces(此处为X替换为清晰度)以进行缩进,因此:

puts [regsub -all "\n" "foo\nBar\nBaz" "\nXX"]
foo
XXBar
XXBaz

这不会缩进第一行,以匹配我使用的第一行^

puts [regsub -all "^" "foo\nBar\nBaz" "\nXX"]

XXfoo
Bar
Baz

现在它应该只是用|来组合两个正则表达式部分,但是我得到输出我无法解释:

puts [regsub -all "^|\n" "foo\nBar\nBaz" "\nXX"]

XXfoo
XX
XXBar
XX
XXBaz

demo

附加换行符和标识符(X)来自哪里?为什么看起来我有两次换人?这是一个错误,还是我对正则表达式语法有点不了解?

对于completnes来说,这是我现在使用的正则表达式puts [regsub -all -line "^" "foo\nBar\nBaz" "XX"]

1 个答案:

答案 0 :(得分:3)

基本与扩展正则表达式

我认为解释取决于表达式^被视为基本正则表达式(BRE)的事实,但是当您添加|时,它被视为高级正则表达式(ARE) ,这是扩展正则表达式(ERE)的超集。这基于以下内容,来自re_syntax man page

  

ARE是一个或多个分支,以“|”分隔,匹配任何与任何分支匹配的内容。

难题的第二部分是^在基本和扩展/高级正则表达式中的区别对待。在基本正则表达式中,^只有在表达式的第一个字符时才有特殊含义。同样,来自re_syntax man page

  

BRE在几个方面与ERE不同... ^除了在RE的开头或带括号的子表达式的开头之外是一个普通的字符,...

换句话说,对于BRE,^仅匹配字符串的开头,但在ARE中它将匹配行的开头。

那么,到底发生了什么?

首先,^匹配字符串的开头,因此将其替换为替换\nXX。接下来,它会看到f,然后是o,然后是o,其中没有一个匹配。然后它会看到匹配的' \ n`,因此它将替换为替换。

此时,匹配器已使用了字符foo\n。剩下的是Bar\nBaz。匹配器现在查看该字符串,模式^匹配,因此它再次替换为替换。因此,您最终得到了两个替换字符串的副本,一个用于换行符,另一个用于剩余字符串的开头。

在每行的开头添加内容

如果你的最终目标是为每一行添加缩进,你可以使用与regsub的换行敏感匹配,然后使用^匹配包括第一行的每一行,而不是尝试匹配新行和开头字符串。您可以通过向--line添加regsub选项来执行此操作。例如:

regsub -line -all "^" "foo\nBar\nBaz" "XX" t; puts $t