zoukankan      html  css  js  c++  java
  • 不区分汉字还是英文和数字,按指定字节长度截取字符串

      Web应用程序在浏览器中显示字符串时,由于显示长度的限制,常常需要将字符串截取后再进行显示。但目前很多流行的语言,如C#、Java内部采用的都是Unicode 16(UCS2)编码,在这种编码中所有的字符都是两个字符,因此,如果要截取的字符串是中、英文、数字混合的,就会产生问题,如下面的字符串:

    String s = "a加b等于c,如果a等1、b等于2,那么c等3";

         上面的字符串既有汉字,又有英文字符和数字。如果要截取前6个字节的字符,应该是”a加b等",但如果用Substring方法截取前6个字符就成了"a加b等于c"。产生这个问题的原因是将Substring方法将双字节的汉字当成一个字节的字符(UCS2字符)处理了。 要解决这个问题的方法是首先得到该字符串的UCS2编码的字节数组,如下面的代码如下:

    byte[] bytes = System.Text.Encoding.Unicode.GetBytes(s);

        然后从第一个字节开始扫描,对于一个英文或数字字符,UCS2编码的第一个字节是相应的ASCII,第二个字节是0,如a的UCS2编码是97  0,而汉字两个字节都不为0,因此,可以利于UCS2编码的这个规则来计算实际的字节数,为了更方便,将按字节长度截取字符串的方法注册为String类的扩展方法,实现代码如下:

    public static class StringExt
        {
            /// <summary>
            /// 格式化超过指定长度的字符串,显示截取后字符串加...
            /// </summary>
            /// <param name="str">字符串</param>
            /// <param name="displayLength">能显示的字节长度</param>
            /// <returns></returns>
            public static string FormatStringLength(this string str, int displayLength)
            {
                //截取后的字符串
                string subStr = string.Empty;
                //字符串生成的默认编码的字节长度
                int nameLenth = Encoding.Default.GetByteCount(str);
                //字符串字节长度大于能显示的字节长度,进行截取
                if (nameLenth > displayLength)
                {
                    //减去将要附加到尾部的"..."的长度,得到要截取的字节长度
                    displayLength = displayLength - 3;
                    //当前遍历到的字节数,是按displayLength计算字节数的,
                    //即汉字算两个字节,英文数字等一个,用来与displayLength比较,好退出循环
                    int CurrentLength = 0;
                    //要截取的字节长度,该长度不同于displayLength,这里是Unicode(USC2)编码,
                    //不区分汉字还是字母,每个字符占两个字节长度
                    int subLength = 0;
                    //字符串生成的Unicode(USC2)编码的字节数组
                    byte[] strBytes = Encoding.Unicode.GetBytes(str);
                    //
                    for (; subLength < strBytes.GetLength(0) && CurrentLength < displayLength; subLength++)
                    {
                        //因为Unicode(USC2)编码时,不区分汉字还是字母,每个字符占两个字节长度,
                        //这里subLength做下标,为0或每次为偶数时,正好是UCS2编码中两个字节的第一个字节,
                        //对于一个英文或数字字符,UCS2编码的第一个字节是相应的ASCII,第二个字节是0,如a的UCS2编码是97 0,而汉字两个字节都不为0
                        //除2的余数为0,表示这是每个字符的第一个字节,字母数字等只在这里对CurrentLength加1,汉字等则在第二个字节处判断出后再加1
                        if (subLength % 2 == 0)
                        {
                            CurrentLength++;
                        }
                        else//除2的余数不为0,表明是一个字符的第二个字节,检查字符的第二个字节
                        {
                            //汉字需要再加上1,以符合默认编码占两个字节
                            if (strBytes[subLength] > 0)
                            {
                                CurrentLength++;
                            }
                        }
                    }
                    //如果subLength为奇数时,即截取的最后一个字符,两个字节中只截取了1个即一般,需处理成偶数
                    if (subLength % 2 == 1)
                    {
                        //对字符的第二个字节进行判断(使用自身做下标,因为下标从0开始,实际检查的就是自己后面的一个字节)
                        //该UCS2字符是汉字时,第二个字节在默认编码中占1个字节,补全的话,长度超限,所以去掉这个截一半的汉字 
                        if (strBytes[subLength] > 0)
                        {
                            subLength = subLength - 1;
                        }
                        else//该UCS2字符是字母或数字,第二个字节在默认编码中不存在,并不占空间,补全该字符
                        {
                            subLength = subLength + 1;
                        }
                    }
                    subStr = Encoding.Unicode.GetString(strBytes, 0, subLength) + "...";
                }
                else//长度未超限,不作格式化
                {
                    subStr = str;
                }
                return subStr;
            }
        }

       在上面的代码中,如果最后要截取奇数个字符(以字节为单位),并且当最后一个字符是字母或数字,则保留该字符,如果是汉字,说明这个汉字被截了一半,则去掉这个汉字。

    可以使用下面的代码来截取字符串:

    string subStr = s.FormatStringLength(6);  //substr的值是"a加b等"
  • 相关阅读:
    在linux CentOS7 安装Nginx 部署vue
    VS Code 用Vue Cli创建项目
    CentOS8通过命令设置IP地址
    C# .net Core WebApi 系列(一)创建与使用
    JS、C#编码解码
    C#通用类库--数字转为人民币汉字大写表示
    CheckUtil类
    Windows服务用bat命令安装与卸载
    突然的兴趣,我想写一个提取图片中特定颜色图像的程序
    一些常用的基础操作记录
  • 原文地址:https://www.cnblogs.com/qfcndtt/p/2827801.html
Copyright © 2011-2022 走看看