解码UTF问题?

我正在研究我的android项目,我有一个异国情调的问题让我发疯。 我正在尝试将字符串转换为Utf-16Utf-8 。 我使用这段代码来实现它但是它给了我一个带有一些负面成员的数组!

Java代码

String Tag="سیر"; String Value=""; try{ byte[] bytes = Tag.getBytes("UTF-16"); for(int i=0;i<bytes.length;i++){ Value=Value+String.valueOf(bytes[i])+","; } 

数组成员 :数组成员是[-1,-2,51,6,-52,6,49,6] 。 我检查了UTF-16的表格。 它没有任何负数,我也使用了一个将单词转换为UTF-16M的网站。 它给了我"0633 06CC 0631" HEX 。 如果将此数字更改为十进制,您将看到: "1577 1740 1585" 。 如你所见,这里没有负数! 所以我的第一个问题是这些负数是什么?!

为什么我要将单词转换为UTF-8或UTF-16?

我正在做一个项目。 这个项目有两个部分。 第一部分是一个Android应用程序,它将关键字发送到服务器。 这些单词由客户发送。 我的客户使用(波斯语,فارسی)字符。 第二部分是由C#制作的Web应用程序,它必须响应我的客户。

问题 :当我将这些单词发送到服务器时,它会在“????”的流上运行 而不是正确的单词。 我已经尝试了很多方法来解决这个问题,但他们无法解决这个问题。 之后我决定将utf-16utf-8字符串自己发送到服务器并将其转换为正确的单词。 所以我选择了我在post顶部描述的方法。

我的原始代码可靠吗?

是的。 如果我使用英文字符,它反应非常好。

我的原始代码是什么?

将参数发送到服务器的Java代码:

  protected String doInBackground(String...Urls){ String Data=""; HttpURLConnection urlConnection = null; try{ URL myUrl=new URL("http://10.0.2.2:80/Urgence/SearchResault.aspx?Tag="+Tag); urlConnection = (HttpURLConnection)myUrl.openConnection(); BufferedReader in = new BufferedReader (new InputStreamReader(urlConnection.getInputStream())); String temp=""; // Data is used to store Server's Response while((temp=in.readLine())!=null) { Data=Data+temp; } } 

响应客户端的C#代码:

  string Tag = Request.QueryString["Tag"].ToString(); SqlConnection con = new SqlConnection(WebConfigurationManager.ConnectionStrings["conStr"].ToString(); SqlCommand cmd = new SqlCommand("FetchResaultByTag"); cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.AddWithValue("@NewsTag",Tag); cmd.Connection = con; SqlDataReader DR; String Txt = ""; try { con.Open(); DR = cmd.ExecuteReader(); while (DR.Read()) { Txt = Txt + DR.GetString(0) + "-" + DR.GetString(1) + "-" + DR.GetString(2) + "-" + DR.GetString(3) + "/"; } //Response.Write(Txt); con.Close(); } catch (Exception ex) { con.Close(); Response.Write(ex.ToString()); } 

*你怎么看 ? 你有什么主意吗 ?**

我解决了 起初我改变了我的java code.i使用URLEncoder类将我的String转换为UTF-8。

新的java代码:

 try{ Tag=URLEncoder.encode(Tag,"UTF-8"); } catch(Exception ex){ Log.d("Er>encodeing-Problem",ex.toString()); } 

之后,我通过Http协议将其作为查询字符串发送

 protected String doInBackground(String...Urls){ String Data=""; HttpURLConnection urlConnection = null; try{ URL myUrl=new URL("http://10.0.2.2:80/Urgence/SearchResault.aspx?Tag="+Tag); urlConnection = (HttpURLConnection)myUrl.openConnection(); BufferedReader in = new BufferedReader (new InputStreamReader(urlConnection.getInputStream())); String temp=""; // Data is used to store Server's Response while((temp=in.readLine())!=null) { Data=Data+temp; } 

最后我抓到服务器并解码它。

新的C#代码:

  string Tag = Request.QueryString["Tag"].ToString(); SqlConnection con = new SqlConnection(WebConfigurationManager.ConnectionStrings["conStr"].ToString()); SqlCommand cmd = new SqlCommand("FetchResaultByTag"); cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.AddWithValue("@NewsTag", HttpUtility.UrlDecode(Tag)); cmd.Connection = con; SqlDataReader DR; String Txt = ""; try { con.Open(); DR = cmd.ExecuteReader(); while (DR.Read()) { Txt = Txt + DR.GetString(0) + "-" + DR.GetString(1) + "-" + DR.GetString(2) + "-" + DR.GetString(3) + "/"; } Response.Write(Txt); con.Close(); } catch (Exception ex) { con.Close(); Response.Write(ex.ToString()); } 

我的第一个问题是这些负数是什么?!

它们是文本的每个16位值中的单个字节的有符号字节表示。 在Java中, byte类型是有符号值,类似于intlong ,但只有8位信息。 它可以表示-128127任何值。 当解释为Java byte值时,它们只是“负数”。

当然,作为UTF16编码文本中的字节,这种解释毫无意义。 您应该只将它们解释为UTF16编码的文本。 但负数是错误解释UTF16编码文本的自然结果,就好像它只是一个普通的有符号字节数组。

它类似于你做过类似int i = -1; uint j = (uint)i;事情int i = -1; uint j = (uint)i; int i = -1; uint j = (uint)i; (在C#中…… Java本身没有无符号整数类型)然后问为什么j 不是负数,而是具有值4,294,967,295 。 嗯, j无符号数据类型; 用作-1作为signed int的位模式与用于4,294,967,295的无符号uint

如果前一段对您没有意义,那么您需要自己做一些阅读,以了解计算机如何存储数字以及有符号和无符号数据类型之间的区别。

代码的输出数组[-1,-2,51,6,-52,6,49,6]实际上是四个 16位值,采用little-endian字节顺序: 0xFEFF0x06330x0631 。 这些16位值中的每一个都代表一个Unicode代码点。

第一个用作UTF16编码文本的字节顺序标记。 它是一个Unicode字符,专门用于指示UTF16编码中的字节是little-endian还是big-endian。 其他三个是实际字符串中的字符。

但是,当您将字节分开并单独查看它们时,如果将其视为有符号字节值,则任何大于0x7F值(当被视为无符号字节值时)都将负数表示为有符号字节值。 因此, 0xFF0xFE0xCC都显示为负数(每个都大于0x7F )。 但它们实际上仍然只是有效的16位Unicode代码点值的一半。

请注意,如果解释不正确,即使这些代码点值也会显示为负数。 在您的示例中,只有一个会显示为负数 – 0xFEFF被解释为带符号的 16位值时为-257 ,即使Unicode代码点实际上是十进制65279 – 但是还有很多其他Unicode字符的值大于0x7FFFF (十进制32767 ),如果被视为带符号的16位值,则会显示为负数。

最重要的是计算机对数字一无所知。 它们只有位,方便地分组为字节和各种字大小。 当您想知道这些位的含义时,您必须确保在向您显示位时告诉计算机正确,有用的表示。 如果不这样做,那么您将获得与其预期表示不匹配的那些位的其他解释。 垃圾进垃圾出。

现在,假设您了解了以上所有内容,让我们考虑您更广泛的问题:

当我将这些单词发送到服务器时,它会在“????”的流上运行 而不是正确的单词。 我已经尝试了很多方法来解决这个问题,但他们无法解决这个问题。

问自己的第一个问题是“我如何解释这些字节?我如何向用户显示它们?” 您没有共享任何在这方面实际相关的代码,但您确实说过,当您仅使用拉丁字母(“英文字符”)时,它可以正常工作。 假设您也使用UTF16测试了拉丁字母方案,那么这告诉我基本I / O工作正常; 你可能遇到的主要问题是字节顺序,但如果发生这种情况,即使拉丁字符也会出现乱码。

所以最可能的解释是"????" 您描述的是,您只是在可以显示波斯语字符的上下文中查看文本。 例如,使用Console类将它们写入控制台窗口。 控制台窗口中使用的字体不支持Unicode感知渲染,因此它不会显示波斯字符。 在其他各种环境中也存在类似的问题,例如记事本(取决于使用的字体)和其他编辑器。

非常抱歉。 以上所有内容实际上只是一种冗长的方式告诉你“一切都很好,你可能只是没有使用正确的工具来validation你的结果。”

请注意,如果没有一个好的, 最小的完整的代码示例可以可靠地再现您感知到的任何问题,那么确实无法确定发生了什么。 如果在阅读并理解了这个答案之后,您仍然认为您的代码存在问题,那么您需要花时间创建一个能够清楚地演示实际问题的良好代码示例。 单行代码值得千言万语,正确的代码示例值得用金重量(混合几个完全不适用的比喻:))。