【问题标题】:TCL: How to convert a very long string into ASCII in TCLTCL:如何在 TCL 中将很长的字符串转换为 ASCII
【发布时间】:2018-07-11 03:10:59
【问题描述】:

我正在尝试将一个很长的字符串转换为 ASCII 十六进制。

我该怎么做呢?

我已经写了这个很长的 switch 语句,但我知道有一种更简单的方法可以做到这一点。我在 switch 语句中遇到了所有奇数符号(如括号、#、$、\ 等)的问题。我可以让其中一些使用反斜杠,但其他一些则失败。

proc Text_to_ASCII {string} {

set Ascii_Word ""

set stringLength [string length $string]

for {set i 0} {$i < $stringLength} {incr i} {

    set Letter [string index $string $i]

    switch -glob $Letter {

        " "     {set hex_ascii 20}

        0   {set hex_ascii 30}
        1   {set hex_ascii 31}
        2   {set hex_ascii 32}
        3   {set hex_ascii 33}
        4   {set hex_ascii 34}
        5   {set hex_ascii 35}
        6   {set hex_ascii 36}
        7   {set hex_ascii 37}
        8   {set hex_ascii 38}
        9   {set hex_ascii 39}

        A   {set hex_ascii 41}
        B   {set hex_ascii 42}
        C   {set hex_ascii 43}
        D   {set hex_ascii 44}
        E   {set hex_ascii 45}
        F   {set hex_ascii 46}
        G   {set hex_ascii 47}
        H   {set hex_ascii 48}
        I   {set hex_ascii 49}
        J   {set hex_ascii 4A}
        K   {set hex_ascii 4B}
        L   {set hex_ascii 4C}
        M   {set hex_ascii 4D}
        N   {set hex_ascii 4E}
        O   {set hex_ascii 4F}
        P   {set hex_ascii 50}
        Q   {set hex_ascii 51}
        R   {set hex_ascii 52}
        S   {set hex_ascii 53}
        T   {set hex_ascii 54}
        U   {set hex_ascii 55}
        V   {set hex_ascii 56}
        W   {set hex_ascii 57}
        X   {set hex_ascii 58}
        Y   {set hex_ascii 59}
        Z   {set hex_ascii 5A}

        a   {set hex_ascii 61}
        b   {set hex_ascii 62}
        c   {set hex_ascii 63}
        d   {set hex_ascii 64}
        e   {set hex_ascii 65}
        g   {set hex_ascii 67}
        h   {set hex_ascii 68}
        i   {set hex_ascii 69}
        j   {set hex_ascii 6A}
        k   {set hex_ascii 6B}
        l   {set hex_ascii 6C}
        m   {set hex_ascii 6D}
        n   {set hex_ascii 6E}
        o   {set hex_ascii 6F}
        p   {set hex_ascii 70}
        q   {set hex_ascii 71}
        r   {set hex_ascii 72}
        s   {set hex_ascii 73}
        t   {set hex_ascii 74}
        u   {set hex_ascii 75}
        v   {set hex_ascii 76}
        w   {set hex_ascii 77}
        x   {set hex_ascii 78}
        y   {set hex_ascii 79}
        z   {set hex_ascii 7A}


        default {set hex_ascii 3F}
    }

append Ascii_Word $hex_ascii

}

return $Ascii_Word
}

所以我一直在尝试这段代码......

proc string2hex {s} {
binary scan $s H* hex
regsub -all (..) $hex {\\x\1}
}

set input_string "lol"

set ascii_string [string2hex $input_string]

返回 "\x6c\x6f\x6c" 这与我想要的“6c6f6c”非常接近 如何删除 \x?我正在考虑只做两次 trimleft 来摆脱每个字符的 \x ,也许一次只喂这个东西一个字符......

想法???

【问题讨论】:

  • 您如何定义这种转换?你想要一个只有 7 位字符的字符串吗?不在 ASCII 集中的字符应该怎么办?您希望得到什么样的字符作为输入?
  • 只有 7 位字符可以在键盘上键入。我需要将书面文字转换为 ASCII。我使用的软件只会接受 ASCII 输入。 “将我转换为 ASCII” 是一个完美的例子。我考虑过在for循环中手动扫描每个字母,然后使用带有char到ascii转换的switch语句,然后将它们拼接在一起,但我猜在tcl中有一种非常简单的方法可以做到这一点使用 [format] 调用,但我对 tcl 不是很了解,也无法弄清楚。
  • 如果我输入“?到 ascii 的 proc 字符串中,我希望返回 3F 的值。我不知道您是否称其为 unicode 值或什么。
  • 我想要达到的目的... UTF-8 是一种将所有 Unicode 字符转换为可变长度字节编码的方法;单个 Unicode 字符可以用一个、两个或三个字节表示。 UTF-8 标准的优势在于它和 Unicode 标准的设计使得与标准 ASCII 集(最多 ASCII 值 0x7F 的十六进制)对应的 Unicode 字符在 UTF-8 和 ASCII 编码中具有相同的字节值。换句话说,大写的“A”字符在 UTF-8 和 ASCII 编码中都由单字节值 0x41 表示。
  • 我添加了一些建议。

标签: string char format tcl ascii


【解决方案1】:

这取决于你的意思。您的意思是真的“将此字符串转换为 ASCII 代码并用 ? 替换未知字符”(或其他字符)还是您的意思是“获取此字符串中所有字符的 Unicode 字符代码”?第二个可能是最有可能的:

proc string_to_ascii {string_value} {
    return [lmap c [split $string_value ""] {
        scan $c %c code
        # Make the code the result of this inner script
        string cat $code
    }]
}

这不是最有效的版本。对于长字符串,事实证明,做这个更长的版本是一个巨大的胜利:

proc string_to_ascii {string_value} {
    set map {}
    set result [lrepeat [string length $string_value] DUMMY]
    set idx 0
    foreach c [split $string_value ""] {
        if {![dict exists $map $c]} {
            scan $c %c ch
            dict set map $c $ch
        }
        lset result $idx [dict get $map $c]
        incr idx
    }
    return $result
}

这是一场胜利有两个原因:

  1. 它预先分配结果列表。这不是必需的,因为 Tcl 的列表确实使用摊销指数增长策略来管理其支持 C 数组,但我们知道我们将获得的长度,因此我们可以变得更聪明。
  2. 它共享整数对象(是的,当然 Tcl 有这些东西;只是 Tcl 的类型系统通常会合谋让你不必担心),这样内存分配的数量大大减少。这实际上与 split 命令在拆分为字符时使用的策略相同(binary scan 也是如此),即使字符串短得惊人,也能取得巨大的性能优势。

但这一切都相当复杂。使用第一个版本(或简单的split $str {},如果您真的不需要立即使用代码点),因为它更容易编写并且内部优化得很好。


为了将字符串强制为 ASCII,您可以这样做:

encoding convertto ascii $input_string

结果技术上是一个字节数组,但作为 ASCII 字符串工作得很好。如果你想检测非ASCII(例如,这样你可以抱怨它),那么你可以改用string is ascii

if {![string is ascii -failindex idx $input_string]} {
    error "found non-ASCII char at index $idx \"[string index $input_string $idx]\""
}

如果你不在乎坏字符在哪里,一个简单的string is ascii $input_string 就可以了。

【讨论】:

    【解决方案2】:

    这是我的最终代码...

    proc Text_to_ASCII {string} {
    
    binary scan $string H* hex
    set Ascii_Word [regsub -all (..) $hex {\1}]
    
    set stackoverflow_users "People who don't have programming jobs because they 
    can't write code with crap are the people who have spare time to answer 
    programming question on stackoverflow"
    }
    

    【讨论】:

      【解决方案3】:

      您应该尝试使用encoding 命令将一种编码转换为另一种编码。一个例子是:

      % encoding convertto ascii "Yen ¥ symbol is not ascii, $ is, and © Copyright also is not."
      --> Yen ? symbol is not ascii, $ is, and ? Copyright also is not.
      

      如果这对您不起作用,请查看string is ascii 命令。

      【讨论】:

        【解决方案4】:

        我相信你正在寻找类似的东西

        binary format a* [encoding convertto ascii $string_value]
        

        结果在我看来确实像 ASCII,尽管我不能确定这是你所追求的。

        更新:我仍然对期望的目标是什么以及为什么现有答案都没有用感到有些困惑。如果预期输入中没有任何字符超出 ASCII 范围,则 UTF-8 字符串与 ASCII 字符串相同:没有要转换的内容。

        如果有个非ASCII字符:转换是有用的:

        % encoding convertto ascii abcåäö
        abc???
        

        结果是一个 UTF-8 / ASCII 字符串。

        如果只需要获取字符串中每个字符的低字节并将每个字符屏蔽为 7 位:

        % join [lmap c [split [binary format a* abcåäö] {}] {format %c [expr {[scan $c %c] & 0x7f}]}] {}
        abcedv
        

        如果要从字符串中获取十六进制代码:

        % binary encode hex abcåäö
        616263e5e4f6
        

        在这种情况下,不进行任何转换(如果输入已经只是 ASCII,这当然可以):结合其他方法获得纯 ASCII,例如:

        % binary encode hex [encoding convertto ascii abcåäö]
        6162633f3f3f
        

        文档: binary, encoding

        【讨论】:

        • 如果我输入一个问号,我想得到3F作为返回值。如果我输入一个空格,我想得到 20 作为返回值。我想我滥用了 ascii 这个词,也许还有其他几个。让我试试你的建议,看看是否可行:)
        猜你喜欢
        • 1970-01-01
        • 2021-09-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-12-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多