通过Native Messaging API读取希伯来文JSON写入文件显示异常求助
问题
使用Tcl代码通过浏览器扩展Native Messaging API接收消息时,能正常读取所有数据,但写入文件时希伯来文等多字节字符被拆分为单个字节显示(例如显示为×”Ö¸×ָֽרֶץ×)。
请问在写入[dict get $msg doc]($msg为HTML大字符串)前需要做什么处理?是stdin配置错误还是写入数据需要编码?
根据MDN文档说明,传入消息为:JSON序列化、UTF-8编码,前缀为本地字节序的无符号32位消息长度值。
附代码:
#!/usr/bin/env tclsh package require json proc coread {reqBytes} { set ::extMsg {} set remBytes $reqBytes while {![chan eof stdin]} { yield append ::extMsg [set data [read stdin $remBytes]] set remBytes [expr {$remBytes - [string length $data]}] if {$remBytes == 0} { return $reqBytes } } throw {COREAD EOF} "Unexpected EOF" } proc ExtRead {} { chan event stdin readable coro_stdin while {1} { set ::extMsg {} chan puts $::fp_log "starting coread 4" if { [coread 4] != 4 || [binary scan $::extMsg iu len] != 1 } { exit } if { [coread $len] != $len } { exit } set msg [::json::json2dict $::extMsg] set book [dict get $msg book] set path "../${book}.html" set fp [open $path w] chan puts $fp [dict get $msg doc] close $fp } } proc CloseConnect {} { set ::forever 0 } proc Listen {} { # Listening on stdin set ::forever 1 chan configure stdin -buffering full -blocking 0 -encoding iso8859-1 -translation crlf coroutine coro_stdin ExtRead vwait forever } set extMsg {} Listen
解决方案
问题出在stdin的编码配置和文件写入时的编码处理两个环节:
修正stdin的编码配置
当前stdin被设为iso8859-1编码,这是单字节编码,会直接拆分UTF-8多字节字符,导致后续解析出的字符串已损坏。Native Messaging传输的是二进制前缀+UTF-8 JSON的组合,需分阶段处理编码:- 读取4字节长度前缀时,将stdin设为二进制模式,避免编码干扰;
- 读取JSON内容时,切换为
utf-8编码,确保完整解析多字节字符; - 解析完成后切回二进制模式,准备下一次读取前缀。
调整后的代码片段:
proc Listen {} { set ::forever 1 # 初始配置为二进制模式,用于读取长度前缀 chan configure stdin -buffering full -blocking 0 -encoding binary -translation binary coroutine coro_stdin ExtRead vwait forever } proc ExtRead {} { chan event stdin readable coro_stdin while {1} { set ::extMsg {} chan puts $::fp_log "starting coread 4" # 读取二进制长度前缀 if { [coread 4] != 4 || [binary scan $::extMsg iu len] != 1 } { exit } # 切换为UTF-8编码读取JSON内容 chan configure stdin -encoding utf-8 -translation binary if { [coread $len] != $len } { exit } # 切回二进制模式,准备下一次循环 chan configure stdin -encoding binary -translation binary set msg [::json::json2dict $::extMsg] set book [dict get $msg book] set path "../${book}.html" # 写入文件时指定UTF-8编码 set fp [open $path w -encoding utf-8] chan puts $fp [dict get $msg doc] close $fp } }文件写入时指定UTF-8编码
打开文件时需显式添加-encoding utf-8参数,确保HTML内容以UTF-8编码保存,避免默认编码导致多字节字符异常。
总结:核心是保证UTF-8数据在读取和写入环节都不被编码转换破坏,分阶段处理stdin的编码模式,同时明确文件写入的编码格式。
内容的提问来源于stack exchange,提问作者Gary
相关产品推荐
相关产品推荐

