Ruby 字符编码怎么判断与转换?Encoding 类有哪些核心方法?

发布时间:2026/9/14 10:09:16
Ruby 字符编码怎么判断与转换?Encoding 类有哪些核心方法? Ruby 字符编码怎么判断与转换Encoding 类有哪些核心方法【免费下载链接】rubyThe Ruby Programming Language项目地址: https://gitcode.com/GitHub_Trending/ru/ruby手头有一段来源不明的字节序列不确定它该按哪种编码解释或者需要把文件从一种编码读到另一种编码——这类问题在 Ruby 里统一由Encoding类和String上的编码方法解决。本文基于 Ruby 仓库的语言文档 encodings.rdoc 和String方法文档给出判断当前编码 → 确认能否拼接 → 重新标注编码 → 真正转码 → 读写流时自动转换这条完整路径所有示例代码均可直接在ruby交互环境或脚本中运行验证。第一步判断字符串当前的编码与有效性每个String对象都带有一个Encoding实例用String#encoding读取。注意拿到编码名只说明字符串自称是什么编码还要用String#valid_encoding?确认字节序列在该编码下确实合法参见 valid_encoding_p.rdocs Straße s.valid_encoding? # true s.encoding # #Encoding:UTF-8 s.force_encoding(Encoding::ASCII).valid_encoding? # false文档给出的另一个常用查询是String#ascii_only?配合valid_encoding?可以判断一段文本是否只是纯 ASCIIs abc.force_encoding(Encoding::UTF_8) # abc s.ascii_only? # true s abc\u{6666}.force_encoding(Encoding::UTF_8) # abc晦 s.ascii_only? # false s \xc2\xa1.force_encoding(Encoding::UTF_8) # ¡ s.valid_encoding? # true s \xc2.force_encoding(Encoding::UTF_8) # \xC2 s.valid_encoding? # false需要区分两种编码不对一种是编码标签错误字节合法但被标成了别的编码用force_encoding改标签即可另一种是字节本身在该编码下非法valid_encoding?返回false必须走转码或清洗路径后文会讲。Symbol和Regexp内部存的字符串也有编码同样可用Symbol#encoding/Regexp#encoding读取两者的默认编码规则是全部字符为 US-ASCII 时是 US-ASCII否则是脚本编码。第二步枚举、查找和别名解析Encoding类的常量就是编码对象每个常量只有一个实例。核心查询方法都在 encodings.rdoc 的 Names and Aliases 一节Encoding.list.size # 103 Encoding.list.first.class # Encoding Encoding.list.take(3) # [#Encoding:ASCII-8BIT, #Encoding:UTF-8, #Encoding:US-ASCII]上面三行输出是文档示例Encoding.list.size的具体数值随环境注册的编码数量变化不必作为固定校验值。按名称或别名找编码对象用Encoding.findname/names/aliases/name_list用于反查一个编码的名字和全部别名Encoding::ASCII_8BIT.name # ASCII-8BIT Encoding::ASCII_8BIT.names # [ASCII-8BIT, BINARY] Encoding::WINDOWS_31J.names # [Windows-31J, CP932, csWindows31J, SJIS, PCK] Encoding.find(US-ASCII) # #Encoding:US-ASCIIEncoding.name_list返回的名字总数多于Encoding.list因为它把别名也算进去了文档示例Encoding.name_list.size # 175同样是示例数值。第三步确认两个字符串能否直接拼接拼接前用Encoding.compatible?检查两个对象是否编码兼容它返回拼接结果将采用的Encoding不兼容时返回nilrus \u{442 435 441 442} eng text Encoding.compatible?(rus, eng) # #Encoding:UTF-8 s0 \xa1\xa1.force_encoding(Encoding::ISO_8859_1) # \xA1\xA1 s1 \xa1\xa1.force_encoding(Encoding::EUCJP) # \x{A1A1} Encoding.compatible?(s0, s1) # nil返回nil意味着这两个字符串不能直接拼接需要先统一编码也就是进入下一步。第四步force_encoding 与 encode 的区别——只改标签还是真正转码这是最容易用错的一对方法。String#force_encoding参见 force_encoding.rdoc不改变底层字节只把编码标签换掉因此即使新标签与内容不匹配也照改不误s łał s.bytes # [197, 130, 97, 197, 130] s.encoding # #Encoding:UTF-8 s.force_encoding(ascii) # \xC5\x82a\xC5\x82 s.encoding # #Encoding:US-ASCII s.valid_encoding? # false s.bytes # [197, 130, 97, 197, 130]也就是说force_encoding适合这段字节本来就是 ISO-8859-1只是被错标了的场景如果字节在新编码下不合法valid_encoding?会立刻给出false这是一个可以直接执行的检查点。String#encode才是真转码参见 encode.rdoc它按给定编码重新解释字节并输出新字符串字节内容通常会变。三种调用形式# 只给目标编码 s Ruby\x99.force_encoding(Windows-1252) t s.encode(UTF-8) # Ruby™ t.encoding # #Encoding:UTF-8 # 同时给目标和源编码按 src_encoding 解释 self再编码为 dst_encoding s Ruby\x99 t s.encode(UTF-8, Windows-1252) # Ruby™ # 不带参数Encoding.default_internal 为 nil 时保持原编码 Encoding.default_internal # nil s Ruby\x99.force_encoding(Windows-1252) t s.encode # 编码与字节都不变两条需要注意的行为都写进了文档默认情况下self含非法字节、或含目标编码未定义的字符时encode会抛异常同一编码到同一编码的转换是 no-op——即使字符串里有非法字节只要没给invalid: :replaces.encode(UTF-8)对 UTF-8 字符串只是原样拷贝不会抛错。想靠encode做同编码校验是行不通的。第五步转码失败时用编码选项决定替换策略encodings.rdoc 的 Encoding Options 一节列出了encode等核心方法接受的关键词参数默认行为都是抛异常可以通过选项改为替换invalid: :replace——非法字节序列替换为替换字符串undef: :replace——目标编码未定义的字符替换为替换字符串:replace默认nil——指定替换串不指定时Unicode 编码默认用\uFFFD其他编码默认用?:fallback——可用 hash、方法或 proc 按每个不可转换的字符定制替换结果:xml: :text/:xml: :attr——按 XML 文本或属性值的规则转义未定义字符。文档示例s \x80foo\x80 s.encode(Encoding::ISO_8859_3) # Raises Encoding::InvalidByteSequenceError. s.encode(Encoding::ISO_8859_3, invalid: :replace) # ?foo? s \xA5foo\xA5 options {:undef :replace, :replace xyzzy} s.encode(Encoding::UTF_8, Encoding::ISO_8859_3, **options) # xyzzyfooxyzzyfallback的 proc 形式文档示例s \u3042foo\u3043 proc Proc.new {|x| x \u3042 ? xyzzy : XYZZY } s.encode(ASCII, fallback: proc) # XYZZYfooXYZZY如果只是想把非法字节洗掉再使用而不做编码转换用String#scrub参见 scrub.rdocfoo\x81\x81bar.scrub # foobar foo\x81\x81bar.force_encoding(US-ASCII).scrub # foo??bar foo\x81\x81bar.scrub(xyzzy) # fooxyzzyxyzzybar foo\x81\x81bar.scrub {|sequence| p sequence; XYZZY } # fooXYZZYXYZZYbar # 块中每次收到的无效序列是 \x81文档示例输出同族方法共六个均会生成新字符串或原地修改String#encode、String#encode!原地、String#scrub、String#scrub!原地、String#unicode_normalize、String#unicode_normalize!原地。其中unicode_normalize接受:nfc/:nfd/:nfkc/:nfkd四种形式参见 unicode_normalize.rdoc且文档明确列出了它支持的编码范围Encoding::UTF_8、Encoding::UTF_16BE/LE、Encoding::UTF_32BE/LE、Encoding::GB18030、Encoding::UCS_2BE、Encoding::UCS_4BE。a\u0300.unicode_normalize # à a\u0300.unicode_normalize(:nfd) # à第六步读写文件时自动转码external/internal 双编码IO、File、ARGF、StringIO这类流对象同时带两个编码external encoding说明流里的字节按什么编码解释。文本流默认 UTF-8二进制流默认 ASCII-8BITinternal encoding若非nil读入的字符串统一转换为该编码。默认是nil不转换。可以在创建流时用 open 选项external_encoding/internal_encoding或简写encoding指定也可以用set_encoding方法支持 BOM 的还有set_encoding_by_bom事后设置。全局默认值可通过命令行-E--external_encoding/--internal_encoding或Encoding.default_external/Encoding.default_internal设置——文档特别提醒运行时用方法改全局默认值可能出问题因为改动前后创建的字符串编码可能不同优先用命令行选项。文档给出的完整示例把字符串按 ISO-8859-1 写入文件再分别按原始字节和转码后两种方式读回。注意这段代码会向当前工作目录写入临时文件t.tmp运行前请确认目录可写s R\u00E9sum\u00E9 path t.tmp ext_enc Encoding::ISO_8859_1 int_enc Encoding::UTF_8 File.write(path, s, external_encoding: ext_enc) raw_text File.binread(path) transcoded_text File.read(path, external_encoding: ext_enc, internal_encoding: int_enc) p raw_text p transcoded_text文档示例输出R\xE9sum\xE9 Résumé第一行是binread得到的原始字节ISO-8859-1第二行是按 internal encoding 转码后的 UTF-8 字符串——这就是同一份文件内容两种编码视图的直接验证方式。第七步确认脚本自身的编码Ruby 脚本有自己的脚本编码用__ENCODING__读取默认 UTF-8。可在源文件第一行有 shebang 时第二行用 magic comment 指定注释必须包含coding或encoding加冒号、空格和编码名或别名# encoding: ISO-8859-1 __ENCODING__ # #Encoding:ISO-8859-1字符串字面量默认就是脚本编码而String.new的规则不同无参数时是 ASCII-8BIT给字符串参数时继承其编码用encoding:关键词可显式指定参见 new.rdoc。注意String.new(foo, encoding: bar)这种不存在的编码名会抛ArgumentError但编码合法而内容不合法的组合不会报错valid_encoding?才会暴露它。边界与易错点小结force_encoding只改标签不改字节字节真的变了才用encode。用valid_encoding?可以立刻判断改标签后内容是否仍合法。encode同编码到同编码是 no-op不校验非法字节需要校验/清洗时用valid_encoding?或scrub。unicode_normalize只支持文档列出的 UTF-16/32 各端序、UTF-8、GB18030、UCS-2BE/4BE其他编码不适用。运行时修改Encoding.default_external/Encoding.default_internal会让改动前后创建的字符串编码不一致文档建议用-E命令行选项设置全局默认。Encoding.compatible?返回nil时两个字符串不可直接拼接先统一编码再操作。完成上面步骤后你可以按encoding查标签 →valid_encoding?查合法性 →compatible?查可拼接性 →encode/scrub处理字节 → 流上用 external/internal 双编码这个顺序处理绝大多数字符串编码问题更多选项细节如:cr_newline/:crlf_newline/:universal_newline换行转换见 encodings.rdoc。【免费下载链接】rubyThe Ruby Programming Language项目地址: https://gitcode.com/GitHub_Trending/ru/ruby创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询