我正在研究我的android项目,我有一个异国情调的问题让我发疯.我正在尝试将字符串转换为Utf-16或Utf-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])+",";
}
Run Code Online (Sandbox Code Playgroud)
数组成员:数组成员是[-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-16或utf-8字符串自己发送到服务器并将其转换为正确的单词.所以我选择了我在帖子顶部描述的方法.
我的原始代码可靠吗?
是的.如果我使用英文字符,它反应非常好.
我的原始代码是什么?
将参数发送到服务器的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;
}
}
Run Code Online (Sandbox Code Playgroud)
响应客户端的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());
}
Run Code Online (Sandbox Code Playgroud)
*你怎么看 ?你有什么主意吗 ?**
我的第一个问题是这些负数是什么?!
它们是文本的每个 16 位值中各个字节的有符号字节表示形式。在 Java 中,byte类型是有符号值,类似于intor long,但只有 8 位信息。-128它可以表示从到 的任何值127。它们仅在被解释为 Javabyte值时才是“负数”。
当然,作为 UTF16 编码文本中的字节,这种解释是没有意义的。您应该仅将它们解释为 UTF16 编码的文本。但负数是误解 UTF16 编码文本的自然结果,就好像它只是一个普通的带符号字节数组。
这类似于您做了类似的事情int i = -1; uint j = (uint)i;(在 C#...Java 本身没有无符号整数类型),然后询问为什么j 不是负数,而是具有值4,294,967,295。嗯,j是一种无符号数据类型;用作有-1符号的位模式与用作无符号的位模式int相同。4,294,967,295uint
如果上一段对您来说没有意义,那么您需要自己阅读一些内容,以了解计算机如何存储数字以及有符号和无符号数据类型之间的区别。
代码的输出数组 ,[-1,-2,51,6,-52,6,49,6]实际上是四个16 位值,采用小端字节顺序:0xFEFF、0x0633、0x06CC和0x0631。每个 16 位值都代表一个 Unicode 代码点。
第一个用作 UTF16 编码文本的字节顺序标记。它是一个Unicode字符,专门用于指示UTF16编码中的字节是小端还是大端。其他三个是实际字符串中的字符。
但是,当您将字节分开并单独查看它们时,如果将其视为有符号字节值,则任何大于0x7F(当视为无符号字节值时)的值都表示负数作为有符号字节值。因此,0xFF、0xFE和0xCCall 显示为负数(每个都大于0x7F)。但它们实际上仍然只是有效 16 位 Unicode 代码点值的每一半。
请注意,如果解释不正确,即使这些代码点值也可能显示为负值。在您的示例中,只有一个会显示为负数 -0xFEFF当-257解释为带符号的16 位值时,即使 Unicode 代码点实际上是十进制65279- 但还有很多其他 Unicode 字符的值高于0x7FFFF(decimal 32767),并且如果将其视为带符号的 16 位值,则将显示为负数。
最重要的是,计算机并不真正了解数字。它们只有位(方便地分组为字节)和各种字大小。当您想知道这些位的含义时,您必须确保告诉计算机在向您显示这些位时要使用的正确、有用的表示形式。如果不这样做,那么您会得到这些位的其他解释,与它们的预期表示不匹配。垃圾进垃圾出。
现在,假设您了解上述所有内容,让我们考虑一下更广泛的问题:
当我将这些单词发送到服务器时,它会在“???”流上运行。而不是正确的词。我尝试了很多方法来解决这个问题,但都无法解决。
要问自己的第一个问题是“我如何解释这些字节?如何向用户显示它们?” 您没有分享任何与这方面实际相关的代码,但您确实说过,当您仅使用拉丁字母(“英语字符”)时,它可以正常工作。假设您也使用 UTF16 测试了拉丁字母场景,那么这告诉我基本 I/O 工作正常;您可能出错的主要问题是字节顺序,但如果发生这种情况,即使是拉丁字符也会出现乱码。
因此,您所描述的最可能的解释"????"是您根本没有在可以显示波斯字符的上下文中查看文本。例如,使用该类将它们写入控制台窗口Console。控制台窗口中使用的字体不支持 Unicode 感知渲染,因此它不会显示波斯语字符。在各种其他环境中也存在类似的问题,包括记事本(取决于使用的字体)和其他编辑器。
非常抱歉。以上所有内容实际上只是对您说“一切都很好,您可能只是没有使用正确的工具来验证您的结果”的冗长方式。
请注意,如果没有一个良好的、最小的、完整的代码示例来可靠地重现您感知到的任何问题,就不可能确定到底发生了什么。如果在阅读并理解这个答案后,您仍然认为您的代码有问题,那么您需要花时间创建一个好的代码示例来清楚地演示实际问题。一行代码胜过一千个单词,而一个正确的代码示例则价值千金(混合几个完全不适用的隐喻:))。