学艺要精,思考要慎.--转UTF-8编码的启发

本文记录了一次从GBK编码迁移到UTF-8编码的过程中遇到的问题及解决方案,特别是针对JSP文件的编码转换,避免了转码工具的使用。

本次对UUZone Refactor中一个大动作就是采用UTF-8编码,由于种种的历史原因,uuzone一直采用GBK编码,现在要把这个编码转成为UTF-8的。

本文不打算讨论技术, 所以简单地说明这个工作进展的一个过程:

* 最早的时候,n年前,我们一个项目需要国际化支持,毫无疑问utf-8是最佳的编码选择,这时候项目组就遇到了问题: 本地编写的文件中的中文都是GBK编码的, 仅仅设置页面的contentType="text/html; charset=UTF-8", 出来的全是乱码...当然拿GBK的东西直接要求对方用UTF-8看,一定是乱码. 

   当时如何解决的过程已经无法了解, 但最终采用的方案是:  用GBK写文件, 然后采用JDK中的native2ascii工具转换. 问题解决了, 但结果就是多了转码的过程, 转码后的jsp文件人不可读.

* 做uuzone了,  项目组建议采用GBK编码, 因为那个转码工作太繁琐了,而且导致文件不可读, 调试非常麻烦. 于是uuzone就成了GBK的.

   由于采用GBK, 遇到了很多相关的问题... 中途至少有2次我"建议"改用UTF-8, 都被评估认为有太多问题而没有被采纳(郁闷的boss啊...)...

* 发现原来不需要转码!  终于处于某些原因, 我需要自己动手来研究一些技术细节, 发现native2ascii转码的工作其实并不需要进行. jsp文件可以直接保存为UTF-8编码, 输出的结果就是UTF-8的...而现在的elips,editplus, ultraedit, 甚至notepad都能保存和识别utf-8的文件.

* 终于下定决心转为UTF-8. 既然如此, 就没有理由拒绝了. 因此本次refactor项目目标之一就是改用UTF-8.  既然文件打算用utf-8保存, 那么就需要批量转换工具...几下search, 好的工具也找到了.

* 转!   有工具, 不到20秒, 6000多个文件就从GBK转成了UTF-8文件格式...

* 问题来了! 项目中的XML, properties文件是否转码呢? 本来计划转...但很快发现,这些文件转掉后, XML,properties文件的读取都出了不同程度的问题...总之项目将根本无法运行... 原因何在?原来这些UTF-8的文件有一个所谓BOM头,也就是告诉你这个文件的编码是什么...不幸的是Java的xml parser, properties文件parser都不认识这个BOM头!已经有人把这个作为Bug提交给了SUN并被接受, 可是这个bug一直拖了4年,才在去年在Mustang项目(Java 6.0)中解决! 我们显然不能用了.

* 幸运的是... 我们可以规避这些问题, 我们并不需要把XML, properties文件转换成UTF-8的, 只要把jsp转了即可. 虽然一个项目中的文件两种保存格式,非常不优雅, 但毕竟这能解决问题啊... 转换完jsp文件,运行项目, 成功! 打开browser...页面也出来了!

* 几乎成功了! 是的, 几乎成功了...然而在计算机的世界里几乎成功就是不成功. 因为页面上的样式神秘地出了轻微的混乱. 经过n十分钟仔细研究讨论, 终于发现产生的html页面内出现了几个神秘的不可见字符... 就是这些可怕的不可见字符, 破坏了页面的结构.

* 神秘的隐身字符  和计算机打交道和比人打交道强的一个地方就是在于 -- 如果计算机错了,一定是你错了, 因为计算机一定忠实执行你的指令. 神秘的不可见字符一定有其来历. 经过二进制分析, 找到了这些神秘字符出现的地方 ---jsp include! 每次include就会出现神秘字符, 而这些神秘字符的值也是老朋友了 -- 就是BOM header ! 

* 难道不能include了?  原来java显然和xml文件一样对待了这些BOM头, 这些FF FE之类的东西成了输出的一部分. google 去查, 看到一个人显然遇到完全相同的问题, 可惜是个俄罗斯的程序员, 也看不懂其文章... :(

    怎么办?  有同学说: 既然你要UTF-8 (心想: 谁让你是boss呢? 愚蠢的boss啊...:-) ) , 我们还是用native2ascii吧...  不行! 

* 遇到困难要思考. 思考...

    首先, 为什么java文件不需要转码(java 文件中的中文无论如何都能正确)? 为什么jsp要? jsp不是被预编译成java的吗? 

    从那个sun承认的bug, 显然可以得出一个结论, java虚拟机中的file input stream没有能自动很具BOM识别文件编码. 

    也许javac是比较native的代码, 能通过操作系统获得native编码类型, 而java内部是unicode的, 所以输出也同样没问题.  而jsp是动态编译的, 预编译器是JVM...其待遇显然和xml等是一样的...

   难道sun公司的人会愚蠢到这种地步? 不可能, 一定是我们愚蠢.继续google 学习...

    不幸的是大部分google上关于这类编码问题的讨论都是不完整的. 但一个神秘的pageEncoding跳进了眼帘, 已经指定了contentType的encoding, 为什么还要指定pageEncoding?  查一下jsp的资料, 显然这正是问题所在!  pageEncoding就是告诉JVM 这个jsp本身采用的encoding, 默认采用iso-8859. 我们明明用GBK的native编码, 让JVM拿iso8859读取,当然不对了!!

* 根本没有需要转码, 问题解决了! 是的, 明白了原因所在, 把所有jsp文件头修改为: <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="GBK" %> 不需要任何转码,最终输出的就是UTF-8, 没有任何问题. 而且这些文件采用native格式保存, 编辑最方便! 

在ROS 2中查找特定设备的驱动程序或集成方法,通常需要考虑以下几个方面: 1. **官方支持**:某些设备可能在ROS 2官方仓库中已经有现成的驱动程序或集成包。对于TM-LRDAE设备,可以通过ROS 2的软件包仓库(如GitHub上的`ros2`组织)进行搜索,查看是否有官方维护的驱动程序。 2. **社区支持**:ROS社区活跃度较高,许多设备的驱动程序由社区维护。可以通过ROS Answers、GitHub仓库或GitLab仓库查找是否已有针对TM-LRDAE的驱动程序或集成指南。 3. **自定义开发**:如果TM-LRDAE设备没有现成的ROS 2驱动程序,可以基于ROS 2的节点开发框架自行实现。这通常包括: - 使用C++或Python编写ROS 2节点。 - 实现设备通信协议(如串口、CAN、I2C、SPI等)。 - 发布或订阅ROS 2话题,将设备数据集成到ROS 2生态系统中。 4. **依赖包安装**:在ROS 2中,类似于`navigation`、`gmapping`和`map-server`等功能包,可能会有类似的依赖项需要安装。可以使用`rosdep`工具来安装依赖: ```bash rosdep install --from-paths src --ignore-src -r -y ``` 5. **硬件抽象层(HAL)**:如果TM-LRDAE设备需要与ROS 2兼容,可能需要先实现硬件抽象层,确保设备的底层通信接口能够被ROS 2调用。 6. **调试与测试**:开发完成后,使用`ros2 launch`和`rqt`工具进行调试,确保设备数据能够正确发布到ROS 2话题中。 如果TM-LRDAE是某种激光雷达(LiDAR)设备,可以参考类似设备的ROS 2驱动程序,例如`rplidar`或`sllidar`的实现方式,作为开发的起点。 ### 示例代码片段 以下是一个简单的ROS 2节点示例,用于模拟设备数据的发布: ```cpp #include "rclcpp/rclcpp.hpp" #include "std_msgs/msg/float32_multi_array.hpp" class TMLRDAENode : public rclcpp::Node { public: TMLRDAENode() : Node("tm_lrdae_node") { publisher_ = this->create_publisher<std_msgs::msg::Float32MultiArray>("tm_lrdae_data", 10); timer_ = this->create_wall_timer( std::chrono::milliseconds(100), [this]() { this->timer_callback(); }); } private: void timer_callback() { auto message = std_msgs::msg::Float32MultiArray(); // 模拟设备数据 message.data = {1.2, 3.4, 5.6, 7.8}; publisher_->publish(message); } rclcpp::Publisher<std_msgs::msg::Float32MultiArray>::SharedPtr publisher_; rclcpp::TimerBase::SharedPtr timer_; }; int main(int argc, char *argv[]) { rclcpp::init(argc, argv); rclcpp::spin(std::make_shared<TMLRDAENode>()); rclcpp::shutdown(); return 0; } ``` ### 调试命令 - 启动节点: ```bash ros2 run tm_lrdae tm_lrdae_node ``` - 查看发布的话题: ```bash ros2 topic list ``` - 订阅设备数据: ```bash ros2 topic echo /tm_lrdae_data ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值