在TCL中,我需要将[fec1 :: 10]:80格式的ipv6地址和端口组合拆分为fec1 :: 10和80。
请建议一种方法。
谢谢!
答案 0 :(得分:2)
(在下面的例子中,我假设地址将受到进一步处理(扩展等),因为它可以采用许多形式:因此,在这个初步阶段我将它简单地视为一串任何字符而不是以冒号分隔的十六进制数字组.kostix提到的ip
包非常适合处理地址,而不是将地址与端口号分开。)
给出变量
set addrport {[fec1::10]:80}
有几种可能的方法,包括强力正则表达式匹配:
regexp -- {\[(.+)\]:(\d+)} $addrport -> addr port
(表示“捕获文字括号内的任何字符的非空序列,然后跳过冒号,然后捕获任何数字的非空序列”;调用结束时的三个变量得到整个匹配,第一个捕获的子匹配,和第二个捕获的子匹配,分别)
(注1:美国人在这里使用'括号'这个词:对于英国人来说,我指的是方括号,而不是圆括号/圆括号)
(注2:我在两个方面使用代码片段->
:作为上例中的变量名称,以及表示某些部分中的返回值的注释符号下面的例子。我希望你不要被它混淆。这两种用法都是一种惯例,在Tcl例子中可以看到很多。)
regexp -inline -- {\[(.+)\]:(\d+)} $addrport
# -> {[fec1::10]:80} fec1::10 80
将为您提供一个包含三个元素的列表(同样,整个匹配,地址和端口)。
许多程序员会停止寻找可能的解决方案,但你仍然和我在一起,不是吗?因为有更多,可能更好的方法。
另一种方法是将字符串转换为双元素列表(其中第一个元素是地址,第二个元素是端口号):
split [string map {[ {} ]: { }} $addrport]
# -> fec1::10 80
(表示“用空字符串替换任何左括号(即删除它们)”和由右括号和带有单个空格的冒号组成的任何子字符串;然后将结果字符串拆分为列表“)
它可以用来分配像这样的变量:
lassign [split [string map {[ {} ]: { }} $addrport]] addr port
(执行从结果列表到两个变量的顺序分配)。
scan
命令也可以工作:
scan $addrport {[%[^]]]:%d} addr port
(表示“在左括号后,取一系列不包括右括号的字符,然后跳过右括号和冒号,然后取一个十进制数字”)
希望将结果改为列表吗?
scan $addrport {[%[^]]]:%d}
# -> fec1::10 80
即使是split
,也会以稍微迂回的方式运作:
set list [split $addrport {[]:}]
# -> {} fec1 {} 10 {} 80
set addr [lindex $list 1]::[lindex $list 3]
set port [lindex $list 5]
(注意:对于扩展到两个以上组的地址,必须重写这个。)
选择,但要记住警惕正则表达式。它们更快,更容易,更诱人,但最终总是咬你的屁股,他们会。
(注意:评论中提到的'Hoodiecrow'是我,我之前使用过那个昵称。另请注意,当这个问题出现时我仍然对ip
模块持怀疑态度:今天我发誓一个人永远不会老去学习,希望如此。)
答案 1 :(得分:2)
答案 2 :(得分:1)
解析这些事情的最简单方法之一是使用scan
。这是许多Tclers忘记的命令!
set toParse {[fec1::10]:80}
scan $toParse {[%[a-f0-9:]]:%d} ip port
puts "host is $ip and port is $port"
诀窍是你需要“scan charcters from limited set”。在生产代码中,您要检查scan
的结果,该结果应该是匹配的组数(在本例中为2)。