處理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/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM