TCL 中十六进制数的全局模式表达式?
Glob pattern expression for a hexadecimal number in TCL?
我正在尝试了解 glob 和正则表达式模式之间的区别。我需要在 TCL 中做一些模式匹配。
目的是查明是否输入了十六进制值。
- 该值可能以也可能不以 0x 开头
- 值应包含 1 到 12 个十六进制字符,即 0-9、a-f、A-F,如果 0x 存在,这些字符应跟在 0x 之后
问题是 glob 不允许使用 {a,b} 来说明要查找的字符数。另外,一开始我尝试使用 (0x[Xx])?但我认为这是行不通的。
使用glob不是必须的。我可以看到 glob 和正则表达式之间存在细微差别。我只想知道这是否只能通过正则表达式而不是 glob 来完成。
The thing is that glob does not allow use of {a,b} to tell about how
many characters to look for. Also, at start I tried to use (0x[Xx])?
but I think this is not working.
一个常用的正则表达式,完全不是 Tcl 特有的,是 ^(0[xX])?[A-Fa-f0-9]{1,12}$
.
更新
正如 Donal 所写,在 regexp
方面存在 power-cost 权衡。我很好奇,并且对于给定的要求(可选 0x
前缀,范围检查 [1,12]
),发现精心制作的脚本使用 string
操作,包括。 string match
(请参阅下面的 isHex1
)在此设置中优于 regexp
(请参阅 isHex2
),无论输入情况如何:
proc isHex1 {str min max} {
set idx [string last "0x" $str]
if {$idx > 0} {
return 0
} elseif {$idx == 0} {
set str [string range $str 2 end]
}
set l [string length $str]
expr {$l >= $min && $l <= $max && [string match -nocase [string repeat {[0-9a-f]} $l] $str]}
}
proc isHex2 {str min max} {
set regex [format {^(0x)?[[:xdigit:]]{%d,%d}$} $min $max]
regexp $regex $str
}
isHex1
扩展了根据输入长度(带或 w/o 前缀)和 string repeat
计算 string match
模式的想法。我自己的计时表明,在最坏的情况下(在范围内,最终字符决定),isHex1
运行速度至少比 isHex2
快 40%(全部使用 time
,10000 次迭代)。其他情况(例如,out-of-range)要快得多。
string match
文档中描述了 glob 语法。与正则表达式相比,glob 是一个生硬的工具。
使用 regular expressions,您将获得标准字符 类,包括 [:xdigit:]
以匹配十六进制数字。
为了与 mrcalvin 的回答形成对比,Tcl-specific 正则表达式为:(?i)^0x[[:xdigit:]]{1,12}$
- 前导
(?i)
表示表达式将匹配case-insensitively.
如果您只关心确定输入是否有效 数字,您可以使用 string is integer
:
set s 0xdeadbeef
string is integer $s ;# => 1
set s deadbeef
string is integer $s ;# => 0
set s 0xdeadbeetle
string is integer $s ;# => 0
Tcl 的 glob 模式比正则表达式 简单得多。他们只支持:
*
表示任意数量的任意字符。
?
表示任何单个字符。
[…]
表示集合中的任何单个字符(括号内的字符,可能包括范围)。
\x
表示文字 x
(可以是任何字符)。这就是将 glob 元字符放入 glob 模式的方式。
它们也总是固定在两端。 (正则表达式更强大。它们也更慢。你为强大付出代价。)
要匹配像 0xF00d
这样的十六进制数字,您需要使用像这样的 glob 模式:
0x[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]
(或者,作为实际的 Tcl 命令;我们将模式放在 {
大括号 }
中以避免所有括号都需要大量反斜杠……)
string match {0x[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]} $value
请注意,我们必须匹配准确数量的字符。 (您可以使用 case-insensitive 匹配将模式缩短为 0x[0-9a-f][0-9a-f][0-9a-f][0-9a-f]
。)
匹配十六进制数最好用 regexp
或 scan
(它也解析十六进制数)。每个人都喜欢忘记 scan
进行解析,但它很擅长......
regexp {^0x([[:xdigit:]]+)$} $value -> theHexDigits
scan $value "0x%x" theParsedValue
我正在尝试了解 glob 和正则表达式模式之间的区别。我需要在 TCL 中做一些模式匹配。
目的是查明是否输入了十六进制值。
- 该值可能以也可能不以 0x 开头
- 值应包含 1 到 12 个十六进制字符,即 0-9、a-f、A-F,如果 0x 存在,这些字符应跟在 0x 之后
问题是 glob 不允许使用 {a,b} 来说明要查找的字符数。另外,一开始我尝试使用 (0x[Xx])?但我认为这是行不通的。
使用glob不是必须的。我可以看到 glob 和正则表达式之间存在细微差别。我只想知道这是否只能通过正则表达式而不是 glob 来完成。
The thing is that glob does not allow use of {a,b} to tell about how many characters to look for. Also, at start I tried to use (0x[Xx])? but I think this is not working.
一个常用的正则表达式,完全不是 Tcl 特有的,是 ^(0[xX])?[A-Fa-f0-9]{1,12}$
.
更新
正如 Donal 所写,在 regexp
方面存在 power-cost 权衡。我很好奇,并且对于给定的要求(可选 0x
前缀,范围检查 [1,12]
),发现精心制作的脚本使用 string
操作,包括。 string match
(请参阅下面的 isHex1
)在此设置中优于 regexp
(请参阅 isHex2
),无论输入情况如何:
proc isHex1 {str min max} {
set idx [string last "0x" $str]
if {$idx > 0} {
return 0
} elseif {$idx == 0} {
set str [string range $str 2 end]
}
set l [string length $str]
expr {$l >= $min && $l <= $max && [string match -nocase [string repeat {[0-9a-f]} $l] $str]}
}
proc isHex2 {str min max} {
set regex [format {^(0x)?[[:xdigit:]]{%d,%d}$} $min $max]
regexp $regex $str
}
isHex1
扩展了根据输入长度(带或 w/o 前缀)和 string repeat
计算 string match
模式的想法。我自己的计时表明,在最坏的情况下(在范围内,最终字符决定),isHex1
运行速度至少比 isHex2
快 40%(全部使用 time
,10000 次迭代)。其他情况(例如,out-of-range)要快得多。
string match
文档中描述了 glob 语法。与正则表达式相比,glob 是一个生硬的工具。
使用 regular expressions,您将获得标准字符 类,包括 [:xdigit:]
以匹配十六进制数字。
为了与 mrcalvin 的回答形成对比,Tcl-specific 正则表达式为:(?i)^0x[[:xdigit:]]{1,12}$
- 前导
(?i)
表示表达式将匹配case-insensitively.
如果您只关心确定输入是否有效 数字,您可以使用 string is integer
:
set s 0xdeadbeef
string is integer $s ;# => 1
set s deadbeef
string is integer $s ;# => 0
set s 0xdeadbeetle
string is integer $s ;# => 0
Tcl 的 glob 模式比正则表达式 简单得多。他们只支持:
*
表示任意数量的任意字符。?
表示任何单个字符。[…]
表示集合中的任何单个字符(括号内的字符,可能包括范围)。\x
表示文字x
(可以是任何字符)。这就是将 glob 元字符放入 glob 模式的方式。
它们也总是固定在两端。 (正则表达式更强大。它们也更慢。你为强大付出代价。)
要匹配像 0xF00d
这样的十六进制数字,您需要使用像这样的 glob 模式:
0x[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]
(或者,作为实际的 Tcl 命令;我们将模式放在 {
大括号 }
中以避免所有括号都需要大量反斜杠……)
string match {0x[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]} $value
请注意,我们必须匹配准确数量的字符。 (您可以使用 case-insensitive 匹配将模式缩短为 0x[0-9a-f][0-9a-f][0-9a-f][0-9a-f]
。)
匹配十六进制数最好用 regexp
或 scan
(它也解析十六进制数)。每个人都喜欢忘记 scan
进行解析,但它很擅长......
regexp {^0x([[:xdigit:]]+)$} $value -> theHexDigits
scan $value "0x%x" theParsedValue