【问题标题】:Decoding UTF Issue?解码 UTF 问题?
【发布时间】:2015-05-07 21:16:37
【问题描述】:

我正在开发我的 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's 表。它没有任何负数,而且我使用了一个将单词转换为 UTF-16M 的网站。它给了我"0633 06CC 0631"HEX。如果将此数字更改为十进制,您将看到:"1577 1740 1585"。如您所见,这里没有负数!所以我的第一个问题是这些负数是什么?!

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

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

问题:当我将这些词发送到服务器时,它会处理“????”流而不是正确的词。我尝试了很多方法来解决这个问题,但他们无法解决。之后,我决定自己将字符串的 utf-16utf-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;        
                    }    
                }

响应客户端的 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());
            }

*你怎么看?你有什么想法吗?**

【问题讨论】:

  • 您正在处理 utf8/16 字符的字节表示。对于您的语言,您将拥有带有高位集的字节,这意味着它们将被视为负数,因为它们被用作有符号整数。
  • 你试过在Tag上使用URLEncoder吗?
  • + value 几乎不是构建 URL/查询字符串的有效方法。这是 C# 解决方案stackoverflow.com/questions/829080/…,应该有等效的 Java 解决方案 - stackoverflow.com/questions/5330104/…...但这与您提出问题的方式无关,因此无法回答...

标签: java c#


【解决方案1】:

我解决了。起初我更改了我的 java 代码。我使用 URLEncoder 类将我的字符串转换为 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());
        }

【讨论】:

    【解决方案2】:

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

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

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

    这类似于你做了类似int i = -1; uint j = (uint)i; 之类的事情(在 C# 中......Java 本身没有无符号整数类型)然后问为什么 j不是负数,取而代之的是4,294,967,295。好吧,j 是一个 unsigned 数据类型;用于-1 作为有符号int 的位模式与用于4,294,967,295 作为无符号uint 的位模式相同。

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


    代码的输出数组[-1,-2,51,6,-52,6,49,6] 实际上是四个 16 位值,以小端字节顺序排列:0xFEFF0x06330x06CC0x0631。这些 16 位值中的每一个都代表一个 Unicode 代码点。

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

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

    请注意,如果解释不正确,即使这些代码点值也可能显示为负数。在您的示例中,即使 Unicode 代码点实际上是十进制 652790xFEFF 被解释为 signed 16 位值时,0xFEFF-257。许多其他 Unicode 字符的值高于 0x7FFFF(十进制 32767),如果将其视为带符号的 16 位值,则会显示为负数。

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


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

    当我将这些词发送到服务器时,它会处理“????”流而不是正确的词。我尝试了很多方法来解决这个问题,但都无法解决。

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

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


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

    请注意,如果没有a good, minimal, complete code example 能够可靠地重现您所感知的任何问题,则实际上不可能确定发生了什么。如果在阅读并理解了这个答案之后,您仍然认为您的代码有问题,您需要花时间创建一个可以清楚地展示实际问题的良好代码示例。一行代码胜过一千字,一个合适的代码示例胜过千金(混合几个完全不适用的隐喻:))。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-06-06
      • 2018-06-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-26
      • 1970-01-01
      • 2018-02-18
      相关资源
      最近更新 更多