zoukankan      html  css  js  c++  java
  • 处理SIM800L模块的中文短信内容

    当SIM800L模块工作在文本模式(AT+CMGF=1),使用AT+CMGR=1读取的非中文短信会直接返回内容,中文短信会显示16进制值,比如:

    +CMGL: 1,"REC UNREAD","10655000531001147525","","20/03/15,16:01:31+32"
    30104F174FE160A054C965C56E3830115C0A656C76844F1A5458FF0C60A876849A8C8BC17801662FFF1A003100370031003900370038FF0C67096548671F003100305206949FFF0C8BF75728987597624E2D586B51996B649A8C8BC17801FF0C8FDB884C540E7EED64CD4F5C3002
    
    // 短信内容为:【众信悠哉旅游】尊敬的会员,您的验证码是:171978,有效期10分钟,请在页面中填写此验证码,进行后续操作。
    

      

    当AT+CSDH=1时,会返回更详细的资料:

    +CMGR: <stat>,<oa>[,<alpha>],<scts>[,<tooa>,<fo>,<pid>,<dcs>,<sca>,<tosca>,<length>]<CR><LF><data>
    

    当AT+CSDH=0时(模块默认值),只会返回:

    +CMGR: <stat>,<oa><CR><LF><data>
    

      

    STM32单片机将短信内容通过SIM800L发送到我们服务器后端时, 如果是中文短信需要将16进制值转换成中文字符串。

    如何在JAVA中转换? 根据【参考资料1】中我们得知,可以用DatatypeConverter类中的parseHexBinary方法:

    String input = "30104F174FE160A054C965C56E383011";
    byte[] bytes = DatatypeConverter.parseHexBinary(input);
    String result = new String(bytes);
    System.out.println(result);
    

      

    然后我就测试了,发现乱码。。。

    查看String类的构造方法【参考资料2】发现可以输入一个字节数组和一个指定的字符集解码,然后我尝试了"UTF-8","GBK",都不行,仍然是乱码。

    然后我就去查了String构造方法中的Charset参数【参考资料3】,发现Charset类中这几类标准字符集:

    Charset    Description
    
    US-ASCII	   Seven-bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the Unicode character set
    ISO-8859-1  	ISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1
    UTF-8	    Eight-bit UCS Transformation Format
    UTF-16BE	  Sixteen-bit UCS Transformation Format, big-endian byte order
    UTF-16LE	  Sixteen-bit UCS Transformation Format, little-endian byte order
    UTF-16	    Sixteen-bit UCS Transformation Format, byte order identified by an optional byte-order mark
    

      

    然后就想了,怎么确定SIM800L模块返回的16进制值用的是哪种编码呢?

    反推吧,我用中文字符串生成这六种编码方式的字节数组,然后将字节数组转换成字符串。

    发现采用的就是 "UTF-16BE",然后我将前面的代码加入指定字符集后测试成功:

    String input = "30104F174FE160A054C965C56E383011";
    byte[] bytes = DatatypeConverter.parseHexBinary(input);
    String result = new String(bytes,"UTF-16BE");
    System.out.println(result);
    

      

    然后我就想看看他们三是啥关系:UTF-16BE UTF-16LE UTF-16,根据【参考资料4

    UTF-16BE:utf-16 big-endian 大端序,也称大尾序

    UTF-16LE:utf-16 little-endian 小端序,也称小尾序

    UTF-16:  基于不同的平台默认使用以上两种尾序,比如苹果Mac系统中 UTF-16 = UTF-16BE;Windows和Linux中 UTF-16 = UTF-16LE。

    上两张直观的图【来源

    看到UTF-16 和UCS-2的关系才想起来,SIM800的中文编码就是采用的UCS-2

    UTF-16可看成是UCS-2的父集。在没有辅助平面字符(surrogate code points)前,UTF-16与UCS-2所指的是同一的意思。但当引入辅助平面字符后,就称为UTF-16了。现在若有软件声称自己支持UCS-2编码,那其实是暗指它不能支持在UTF-16中超过2字节的字集。对于小于0x10000的UCS码,UTF-16编码就等于UCS码。

    然后我就回过头去测试了一下 "UTF-16"字符集 发现也OK

    根据【这里】的资料说明,Java平台中UTF-16默认使用大端序,所以指定UTF-16字符集也可以成功解码。

    参考资料1:https://www.baeldung.com/java-base64-encode-and-decode

    参考资料2:https://docs.oracle.com/javase/7/docs/api/java/lang/String.html

    参考资料3:https://docs.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html

    参考资料4:https://zh.wikipedia.org/wiki/UTF-16

    参考资料5:https://zh.wikipedia.org/wiki/%E5%AD%97%E8%8A%82%E5%BA%8F#%E5%A4%A7%E7%AB%AF%E5%BA%8F

    参考资料6:https://xiaogd.net/%E7%BD%91%E9%A1%B5%E4%B8%AD%E7%9A%84%E7%BC%96%E7%A0%81%E4%B8%8E%E4%B9%B1%E7%A0%81%EF%BC%884%EF%BC%89/

  • 相关阅读:
    PAT B1021 个位数统计 (15)
    PAT B1006 换个格式输出整数 (15)
    PAT A1058 A+B in Hogwarts (20)
    PAT A1027 Colors in Mars (20)
    PAT A1019 General Palindromic Number (20 分)
    PAT B1022 D进制的A+B
    J2EE
    MVC
    数据库长连接短连接
    twisted
  • 原文地址:https://www.cnblogs.com/1x11/p/12507175.html
Copyright © 2011-2022 走看看