如何将字符串拆分为TCL中的单词列表,忽略多个空格?

时间:2012-11-14 14:38:04

标签: string split tcl

基本上,我有一个由多个空格分隔的单词组成的字符串。然而,事情是,可以有多个空格而不是只有一个分隔单词。这就是为什么[split]没有做我想做的事情:

split "a    b"

给了我这个:

{a {} {} {} b}

而不是:

{a b}

在搜索Google时,我找到了a page on the Tcler's wiki,用户提出的问题大致相同。

一个建议的解决方案看起来像这样:

split [regsub -all {\s+} "a    b" " "]

似乎适用于简单的字符串。但是[string repeat " " 4]之类的测试字符串(因为StackOverflow剥离了多个空格而使用了字符串重复)将导致regsub返回“”,split会再次分成{{} {}}一个空列表。

另一个提议的解决方案是这个,强制重新解释给定字符串作为列表:

lreplace "a   list   with many   spaces" 0 -1

但是如果有一件事我已经了解了TCL,那就是你永远不应该在字符串上使用列表函数(以l开头)。事实上,这个会阻塞包含特殊字符的字符串(即{和}):

lreplace "test    \{a b\}"

返回test {a b}而不是test \{a b\}(这就是我想要的,每个以空格分隔的单词都会分成结果列表的单个元素)。

另一个解决方案是使用'过滤器':

proc filter {cond list} {
    set res {}
    foreach element $list {if [$cond $element] {lappend res $element}}
    set res
}

然后你就这样使用它:

filter llength [split "a   list   with many   spaces"]

同样,同样的问题。这将在一个字符串上调用llength,该字符串可能包含特殊字符(同样,{和}) - 传递它“\ {ab \}”会导致TCL抱怨“列表中无法匹配的开括号”。 / p>

我设法通过修改给定的filter函数来实现它,在if中的$ cond前面添加了{*},因此我可以将其与string length而不是{{{{}}一起使用1}},这似乎适用于我到目前为止尝试使用它的每一个可能的输入。

此解决方案现在可以安全使用吗?到目前为止我还没有测试一些特殊的输入吗?或者,是否可以以更简单的方式执行正确的

1 个答案:

答案 0 :(得分:15)

最简单的方法是使用regexp -all -inline选择并返回所有单词。例如:

# The RE matches any non-empty sequence of non-whitespace characters
set theWords [regexp -all -inline {\S+} $theString]

如果您将单词定义为字母数字序列,则将其用于正则表达式术语:{\w+}