6

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

split "a    b"

给了我这个:

{a {} {} {} b}

而不是这个:

{a b}

搜索 Google,我在 Tcler 的 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 抱怨“列表中不匹配的左大括号”。

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

这个解决方案现在可以安全使用吗?它会不会因为我到目前为止没有测试过的一些特殊输入而窒息?或者,是否有可能以更简单的方式做到这一点

4

2 回答 2

16

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

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

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

于 2012-11-14T15:49:18.687 回答
0

您可以改用正则表达式: 来自tcl wiki split

按空格分割:陷阱

split { abc def  ghi}
{} abc def {} ghi

通常,如果您按空格分割并且不想要那些空白字段,那么您最好这样做:

regexp -all -inline {\S+} { abc def  ghi}
abc def ghi
于 2022-01-11T11:59:24.953 回答