Tcl用于获取字符串中每个字符的ASCII码

7
我需要获取字符串中每个字符的ASCII码。实际上是一个(小)文件中的每个字符。以下前三行成功地将文件的所有内容提取到字符串中(参见this recipe)。
set fp [open "store_order_create_ddl.sql" r]
set data [read $fp]
close $fp

我相信我正确地识别了字符的ASCII码(请参见http://wiki.tcl.tk/1497)。但是,我在解决如何循环遍历字符串中的每个字符时遇到了问题。
首先,我不认为以下是使用Tcl循环遍历字符串中的字符的特别惯用的方法。其次,更重要的是,它的行为不正确,在每个字符之间插入了一个额外的元素。
下面是我编写的用于操作上面设置的"data"变量内容的代码,以及一些示例输出。
代码:
for {set i 0} {$i < [string length $data]} {incr i} {
  set char [string index $data $i]
  scan $char %c ascii
  puts "char: $char (ascii: $ascii)"
}

输出:

char: C (ascii: 67)
char:  (ascii: 0)
char: R (ascii: 82)
char:  (ascii: 0)
char: E (ascii: 69)
char:  (ascii: 0)
char: A (ascii: 65)
char:  (ascii: 0)
char: T (ascii: 84)
char:  (ascii: 0)
char: E (ascii: 69)
char:  (ascii: 0)
char:   (ascii: 32)
char:  (ascii: 0)
char: T (ascii: 84)
char:  (ascii: 0)
char: A (ascii: 65)
char:  (ascii: 0)
char: B (ascii: 66)
char:  (ascii: 0)
char: L (ascii: 76)
char:  (ascii: 0)
char: E (ascii: 69)

虽然我对TCL一无所知,但从输出结果来看,我可以告诉你的是,你的输入字符串是UTF-16编码的,具体来说是UTF-16小端字节序,而不是ASCII编码。 - Arthur Reutenauer
Arthur,感谢您的评论,但我非常想知道,您是如何从输出中确定它是UTF-16小端编码的? - Dexygen
2
UTF-16使用两个字节单元来编码字符。对于前65536个Unicode字符(即所谓的平面0),它使用其中一个单元,对于所有其余字符,它使用两个单元(即4个字节,但分别编码为两个代理字符,每个字符编码为两个字节)。 ASCII字符形成了前128个Unicode字符,因此它们使用两个字节进行编码,最高有效位始终为0,最低有效位等于字符的ASCII代码。在这里,您可以看到每个ASCII代码后面跟着一个空字节,因此您需要按最小顺序字节排列,即UTF-16LE。 - Arthur Reutenauer
谢谢Arthur,这比我同时查阅的维基百科文章更清晰! - Dexygen
Arthur,请考虑将此内容撰写为答案而非评论,我一定会点赞并且很可能接受它;这样你就可以因为你的贡献获得一些声望。 - Dexygen
PS...这是我遇到的问题:我本来想用PHP解析输出,但在尝试对数据进行标记化时遇到了segfaults错误。通过PHP,我确定存在内部空字符,并且认为可能与文件传输有关,首先通过远程桌面,然后通过SCP。我排除了后者,所以为了确保问题不是因为a)PHP和b)通过远程桌面传输,我随后上传了TCLKit到远程桌面,以便可以尝试另一种语言,在生成SQL的机器上直接运行。 - Dexygen
2个回答

12
以下代码应该有效:
set data {CREATE TABLE}
foreach char [split $data ""] {
    lappend output [scan $char %c]
}
set output ;# 67 82 69 65 84 69 32 84 65 66 76 69

关于输出中多余的字符,看起来问题出在你从文件中获取的输入数据上。是否有某种原因导致文件中每个字符之间都存在空字符(\0)?


我已经开始怀疑这可能是输入的问题了,尽管每个字符之间没有空字符的好理由,除了它是用 Microsoft(SQL Server)工具生成的 ;) - Dexygen
那么这就是你的答案。大多数微软工具(顺便提一句,还有苹果的工具)使用UTF-16作为它们的内部编码;因为这是本机Intel字节序,所以UTF-16LE更为普遍。您需要告诉Tcl将输入文件解释为UTF-16。再次,我不知道如何做到这一点,很抱歉,但您应该在文档中寻找类似“编码”或“字符集”或通常情况下是Unicode的关键字。 - Arthur Reutenauer
在打开文件之后但在读取文件内容之前,您可能想要执行以下操作:fconfigure $fp -encoding unicode。 - Colin Macleod

0

在寻找其他内容时,遇到了这个较旧的问题。为了让其他可能正在寻找答案的人受益,我来回答一下。

首先,要理解字符编码是什么。在示例中,源数据并不是ASCII字符编码,因此ASCII字符代码(代码0-127)实际上没有意义——除非在这个示例中,编码似乎是UTF-16,其中包括ASCII代码作为子集。你可能想要的是从0到255的完整范围的“字符”代码,但是根据你的系统、数据来源等,代码128-255可能是ANSI、ISO或其他奇怪的代码页。你需要做的是将数据转换为你知道如何处理的格式,例如非常常见的ISO 8859-1代码(编码“iso8859-1”),它非常类似于Windows 1252标准编码(编码“cp1252”),或者使用“encoding”命令的UTF-8(编码“utf-8”):

set data [encoding convertto utf-8 $data] ;# 对于UTF-8

set data [encoding convertto iso8859-1 $data] ;# 对于ISO 8859-1

等等。如果您正在从文件中读取数据,您可能还想在读取数据之前设置文件编码(通过fconfigure),以确保正确读取文件数据。查阅“编码”(和“fconfigure”)的手册页面,了解有关处理字符集编码的更多详细信息。

一旦您掌握了数据的编码,其余的示例代码应该按预期工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接