基本上,我有一个由多个空格分隔的单词组成的字符串。然而,事情是,可以有多个空格而不是只有一个分隔单词。这就是为什么[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}},这似乎适用于我到目前为止尝试使用它的每一个可能的输入。
此解决方案现在可以安全使用吗?到目前为止我还没有测试一些特殊的输入吗?或者,是否可以以更简单的方式执行正确的?
答案 0 :(得分:15)
最简单的方法是使用regexp -all -inline
选择并返回所有单词。例如:
# The RE matches any non-empty sequence of non-whitespace characters
set theWords [regexp -all -inline {\S+} $theString]
如果您将单词定义为字母数字序列,则将其用于正则表达式术语:{\w+}