6

基本的に、スペースで区切られた複数の単語で構成される文字列があります。ただし、単語を区切るスペースは 1 つだけではなく、複数のスペースが存在する可能性があります。これが[split]私が望むことをしない理由です:

split "a    b"

私にこれを与える:

{a {} {} {} b}

これの代わりに:

{a b}

Google で検索したところ、Tcler の wikiで、あるユーザーが多かれ少なかれ同じ質問をしているページを見つけました。

提案されたソリューションの 1 つが次のようになります。

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

これは単純な文字列で機能するようです。[string repeat " " 4]ただし、 (StackOverflow が複数のスペースを削除するため、文字列の繰り返しを使用)などのテスト文字列はregsub" " を返し、空のリストではなくsplit再び分割されます。{{} {}}

別の提案された解決策は、指定された文字列をリストとして再解釈することを強制する次の解決策でした。

lreplace "a   list   with many   spaces" 0 -1

しかし、TCL について私が学んだことが 1 つあるとすれば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 に答える