TCL和将字符串的部分拆分成整数

时间:2014-02-28 14:01:21

标签: string tcl

我有一个字符串,我想将它的一部分转换为不同的整数变量。例如我有字符串:“some text,0x0110,0xa0,0xff,0x02”

从这一点开始我希望var1 = 0x02,var2 = 0xff,var3 = 0xa0,var4 = 0x02

任何人都有使用tcl和字符串的经验,可以帮助我吗?

2 个答案:

答案 0 :(得分:3)

假设

set str "some text,0x0110, 0xa0, 0xff, 0x02"

如果您只想要这些值,可以使用此命令返回值列表:

scan $str "some text,%x,%x,%x,%x"
# -> 272 160 255 2

(它要求scan命令查找并提取由逗号分隔的四个十六进制值字段(带有可选的空格),并以前缀字符串开头。)

如果要直接将这些值分配给变量,请调用这样的命令(在这种情况下,它会返回读取的字段数,这是一件好事,因为任何数字都不等于你的字段数放入表示出现了问题):

scan $str "some text,%x,%x,%x,%x" var1 var2 var3 var4
# -> 4

如果要将值存储为十六进制文字,则此命令可能会执行以下操作:

scan $str {some text, %[^,], %[^,], %[^,], %[^,]} var1 var2 var3 var4

(它指定字段应该包含除逗号之外的任何字符,否则它与之前的字符相同。在这种情况下,需要在格式字符串之前指定逗号之后的空格:空格字符表示零或应跳过更多的空格,制表符或换行符。必须使用大括号来防止Tcl将方括号解释为嵌入式命令。)

另一种变体:

scan $str {some text, %[xX0-9a-fA-F], %[xX0-9a-fA-F], %[xX0-9a-fA-F], %[xX0-9a-fA-F]} var1 var2 var3 var4

(这个字段指定的字符串是由字符x(大写或小写)和十六进制数字组成的字符串,按某种顺序排列。)

这有点笨拙。你可以通过构建它来使它变得不那么复杂:

set X {%[xX0-9a-fA-F]}
# -> %[xX0-9a-fA-F]
set fmt [join [concat {{some text}} [lrepeat 4 $X]] {, }]
# -> some text, %[xX0-9a-fA-F], %[xX0-9a-fA-F], %[xX0-9a-fA-F], %[xX0-9a-fA-F]
scan $str $fmt var1 var2 var3 var4

有更多方法可以做到这一点。你不能将它直接拆分成一个列表,因为split $str {, }将分为逗号或空格,而不是字符串逗号+空格(嗯,你可以,但它不是真的方便)。但是:如果您首先将所有逗号+空格字符串转换为逗号,split变得有用:

string map {{, } ,} $str
# -> some text,0x0110,0xa0,0xff,0x02
split [string map {{, } ,} $str] ,
# -> {some text} 0x0110 0xa0 0xff 0x02
lrange [split [string map {{, } ,} $str] ,] 1 end
# -> 0x0110 0xa0 0xff 0x02

导致:

lassign [lrange [split [string map {{, } ,} $str] ,] 1 end] var1 var2 var3 var4

为您提供所需的作业。

我在思考是否要解释基于正则表达式的提取,但现在我看到glenn jackman *已经做到了。为了完整起见,我还会在我的回答中简单提一下它,但除了他的所作所为之外我几乎没有什么可说的:

regexp -inline -all -- {0[xX][[:xdigit:]]+} $str
# -> 0x0110 0xa0 0xff 0x02
lassign [regexp -inline -all -- {0[xX][[:xdigit:]]+} $str] var1 var2 var3 var4

我的定义与glenn之间存在一些差异。他正在使用单词锚(\m\M),这在这里似乎并不十分必要(但在一些奇特的情况下可能会有用:使用它们当然没有错)。他还匹配十六进制数前缀中的文字x:我更喜欢匹配大写或小写x([xX])。在实践中,十六进制文字几乎总是写成0x...,但你永远不能确定。因此,差异归结为他想要以一种方式更加确定,而我希望在另一种方式中更加确定。

调用regexp表示返回匹配列表(-inline),以匹配正则表达式(-all)的所有匹配项,并匹配包含的匹配项零个字符(0),后跟大写或小写x字符([xX]),后跟一个或多个(+)次出现的{[ .. 。])十六进制数字([:xdigit:])。同样,表达式周围的大括号阻止Tcl尝试将方括号内的文本作为命令进行评估。

使用的命令(指向手册页的链接):setscanjoinconcatlrepeat,{ {3}},stringsplitlrangelassign

*)杰克曼先生确实签了他的名字。在所有小写字母中写下别人的名字感觉很奇怪而且含糊不清,但OTOH改变别人自己选择写名字的方式也感觉不对。

答案 1 :(得分:2)

使用正则表达式

提取值
% set s "some text,0x0110, 0xa0, 0xff, 0x02"
some text,0x0110, 0xa0, 0xff, 0x02
% set xnums [regexp -inline -all {\m0x[[:xdigit:]]+\M} $s]
0x0110 0xa0 0xff 0x02
% lassign $xnums var1 var2 var3 var4