gpt4 book ai didi

ruby - Net::Telnet - 以 UTF-8 格式放置或打印字符串

转载 作者:数据小太阳 更新时间:2023-10-29 07:59:47 25 4
gpt4 key购买 nike

我正在使用一个 API,其中我必须通过 telnet 连接将客户端信息作为 Json 对象发送(很奇怪,我知道^^)。
我是德国人,所以客户信息经常包含变音或 ß。

我的程序:

  • 我生成一个包含所有命令信息的哈希。
  • 我将哈希转换为 Json 对象。
  • 我将 Json 对象转换为字符串(使用 .to_s )。
  • 我使用 Net::Telnet.puts 命令发送字符串。

  • 我的 puts命令看起来像:(cmd 是 Json 对象)
    host.puts(cmd.to_s.force_encoding('UTF-8'))

    在我看到的日志文件中,Json 对象不包含变音符号,但例如: ü而不是 ü .

    我证明该字符串是 UTF-8 格式的(有或没有 force_encoding() 命令)。所以我认为 puts命令不会以 UTF-8 格式发送字符串。

    是否可以以 UTF-8 格式发送命令?我怎样才能做到这一点?

    整个方法:
    host = Net::Telnet::new(
    'Host' => host_string,
    'Port' => port_integer,
    'Output_log' => 'log/'+Time.now.strftime('%Y-%m-%d')+'.log',
    'Timeout' => false,
    'Telnetmode' => false,
    'Prompt' => /\z/n
    )

    def send_cmd_container(host, cmd, params=nil)
    cmd = JSON.generate({'*C'=>'se','Q'=>[get_cmd(cmd, params)]})
    host.puts(cmd.to_s.force_encoding('UTF-8'))
    add_request_to_logfile(cmd)
    end

    def get_cmd(cmd, params=nil)
    if params == nil
    return {'*C'=>'sq','CMD'=>cmd}
    else
    return {'*C'=>'sq','CMD'=>cmd,'PARAMS'=>params}
    end
    end

    添加:

    我还通过这种方法记录我发送的请求:
    def add_request_to_logfile(request_string)
    directory = 'log/'
    File.open(File.join(directory, Time.now.strftime('%Y-%m-%d')+'.log'), 'a+') do |f|
    f.puts ''
    f.puts '> '+request_string
    end
    end

    在日志文件中,我的请求也不包含 UTF-8 变音符号,但例如: ü

    最佳答案

    TL; 博士

    套装'Binmode' => true并使用 Encoding::BINARY .

    以上应该对你有用。如果您对原因感兴趣,请继续阅读。

    Telnet 并没有真正的“编码”概念。 Telnet 只有两种模式:普通模式假设您发送的是 7 位 ASCII 字符,而二进制模式假设您发送的是 8 位字节。您不能告诉 Telnet “这是 UTF-8”,因为 Telnet 不知道这意味着什么。您可以告诉它“这是 ASCII-7”或“这是一个 8 位字节序列”,仅此而已。

    这似乎是个坏消息,但实际上是个好消息,因为 UTF-8 恰好将文本编码为 8 位字节序列。 früh例如,是五个字节:66 72 c3 bc 68 .这在 Ruby 中很容易确认:

    puts str = "\x66\x72\xC3\xBC\x68"
    # => früh
    puts str.bytes.size
    # => 5

    在 Net::Telnet 中,我们可以通过传递 'Binmode' => true 来打开二进制模式。选项 Net::Telnet::new .但是我们还需要做一件事:告诉 Ruby 将字符串视为二进制数据,即 8 位字节序列。

    您已经尝试使用 String#force_encoding ,但您可能没有意识到 String#force_encoding实际上不会将字符串从一种编码转换为另一种编码。它的目的不是改变数据的编码——它的目的是告诉 Ruby 数据已经采用了什么编码:
    str = "früh"   # => "früh"
    p str.encoding # => #<Encoding:UTF-8>
    p str[2] # => "ü"

    p str.bytes # => [ 102, 114, 195, 188, 104 ] # This is the decimal represent-
    # ation of the hexadecimal bytes
    # we saw before, `66 72 c3 bc 68`

    str.force_encoding(Encoding::BINARY) # => "fr\xC3\xBCh"
    p str[2] # => "\xC3"

    p str.bytes # => [ 102, 114, 195, 188, 104 ] # Same bytes!

    现在我要告诉你一个小 secret : Encoding::BINARY只是 Encoding::ASCII_8BIT 的别名.由于 ASCII-8BIT 没有多字节字符,Ruby 显示 ü作为两个单独的字节, \xC3\xBC .这些字节不是 ASCII-8BIT 中的可打印字符,因此 Ruby 显示 \x##转义码,但数据没有改变——只是 Ruby 打印它的方式改变了。

    所以事情是这样的:即使 Ruby 现在调用字符串 BINARY 或 ASCII-8BIT 而不是 UTF-8,它仍然是相同的字节,这意味着它仍然是 UTF-8。但是,更改它“标记”为的编码意味着 Net::Telnet 执行(相当于) data[n]它总是会得到一个字节(而不是像 UTF-8 那样可能得到多字节字符),这正是我们想要的。

    所以...
    host = Net::Telnet::new(
    # ...all of your other options...
    'Binmode' => true
    )

    def send_cmd_container(host, cmd, params=nil)
    cmd = JSON.generate('*C' => 'se','Q' => [ get_cmd(cmd, params) ])
    cmd.force_encoding(Encoding::BINARY)
    host.puts(cmd)
    # ...
    end

    (注意: JSON.generate 总是返回一个 UTF-8 字符串,所以你永远不必这样做,例如 cmd.to_s 。)

    有用的诊断

    检查 Net::Telnet 实际发送(和接收)哪些数据的快速方法是设置 'Dump_log'选项(与您设置 'Output_log' 选项的方式相同)。它将发送和接收的数据以十六进制转储格式写入日志文件,这将允许您查看发送的字节是否正确。例如,我启动了一个测试服务器( nc -l 5555 )并发送了字符串 früh ( host.puts "früh".force_encoding(Encoding::BINARY) ),这是记录的内容:

    > 0x00000: 66 72 c3 bc  68 0a                                  fr..h.


    可以看到它发送了六个字节:前两个是 fr ,后面两个补 ü ,最后两个是 h和换行符。在右侧,不可打印字符的字节显示为 . , ergo fr..h. . (出于同样的原因,我发送了字符串 I❤NY 并在右栏中看到了 I...NY.,因为 是 UTF-8 中的三个字节: e2 9d a4 )。

    所以,如果你设置 'Dump_log'并发送 ü ,你应该看到 c3 bc在输出中。如果你这样做了,恭喜你——你发送的是 UTF-8!

    附言阅读 Yehuda Katz 的文章 Ruby 1.9 Encodings: A Primer and the Solution for Rails .事实上,每年都要阅读它。真的,真的很有用。

    关于ruby - Net::Telnet - 以 UTF-8 格式放置或打印字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25627795/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com