用C#截取指定长度的中英文混合字符串

转自https://bbs.csdn.net/topics/340153141

通常,一个中文会占两个字节的空间。很多语言里,一个中文字符就算是2个字符长度。
但在C#中,string里包含的中文字符只占一个字符长度。这就导致很多时候,使用string.SubString(int startIndex,int length)方法来截取字符会错位。
最近由于工作原因,会截取指定长度的字符来使用。但是在文档里,1个中文是2个长度来计算。刚开始还只是以为文档错误,后来才知道是由于C#的差异造成的。
刚开始,是直接到网上找算法,但是找到的算法,基本思路都是挨个字符判断(根据ASCII值)。不是算法复杂,就是容易出错,且不能涵盖所有的中文。
稍微研究了下,还是利用.Net框架自带的方法最简单。
基本思路如下,将string转化为byte[] ,将byte[]截取后,再转化为string ,这种方法,两步完成,且可谓万无一失。

public static string SubString(string toSub,int startIndex,int length)

{
    byte[] subbyte=System.Text.Encoding.Default.GetBytes(toSub);
    string Sub=System.Text.Encoding.Default.GetString(subbyte,stratIndex,length);
    return Sub;
}

稍微解释下参数,toSub -需要截取的字符串,startIndex -开始截取的位置索引, length -截取的长度
用法基本和string.SubString(int startIndex,int length)一样。

 

后来有大神文章

http://www.cnblogs.com/yao/archive/2008/03/06/1093066.html

很早以前写过一篇文章(用C#截取指定长度的中英文混合字符串),但是对性能没有测试,有人说我写的这个方法性能有问题,后来想,可能真会有BT之需求要求传入一个几万K甚至几M体积的字符串进来,那将会影响正则Match的速度,比如文章系统中就极有可能用到,今天有点时间,就改进了一下,代码如下:
 

    public static string getStr(string s,int l,string endStr)
    
{
        
string temp = s.Substring(0, (s.Length < l)?s.Length:l);
        
        
if (Regex.Replace(temp,"[\u4e00-\u9fa5]","zz",RegexOptions.IgnoreCase).Length<=l)
        
{
            
return temp;
        }

        for (int i=temp.Length;i>=0;i--)
        
{
            temp 
= temp.Substring(0,i);
            
if (Regex.Replace(temp,"[\u4e00-\u9fa5]","zz",RegexOptions.IgnoreCase).Length<=l-endStr.Length)
            
{
                
return temp + endStr;
            }
    
        }

        return endStr;
    }



此修改版的方法多加了个参数"string endStr",是指当字符串"string s"超过指定长度"int l"时,对结尾的处理,比如要不要加上省略号"..."或加上其它字符。
另外,添加了省略号之后,省略号长度也是算在结果的长度之内了。

    用法如:

    getStr("中国1中国中国中1111中国", 23,"") 
    //output:中国1中国中国中1111中国

    getStr("中国1中国中国中1111中国", 23,"...") 
    //output:中国1中国中国中1111...

    getStr("中国1中国中国中1111中国中国", 23,"")    
    //output:中国1中国中国中1111中国

    getStr("中国1中国中国中1111中国中国", 23,"...")
    //output:中国1中国中国中1111...

----------------------------------------------------------------------

    补充:"kpz"回复说上边的方法会截取失真,而我又无法做到穷尽测试,所以换了另一种写法,为了考虑性能结果把逻辑搞的有点"晕",反复测试了多次,代码如下:

 

public static string getStr2(string s, int l,string endStr) 
    

        
string temp = s.Substring(0, (s.Length < l+1)?s.Length:l+1);    
        
byte[] encodedBytes = System.Text.ASCIIEncoding.ASCII.GetBytes(temp);
        
        
string outputStr = ""
        
int count = 0;     
        
        
for (int i = 0; i < temp.Length; i++
        

            
if ((int)encodedBytes[i] == 63)
                count 
+= 2
            
else
                count += 1

            
if (count <= l-endStr.Length)
                outputStr 
+= temp.Substring(i,1); 
            
else if (count>l)    
                
break;            
        }
 
        
        
if (count<=l)
        
{
            outputStr
=temp;
            endStr
="";
        }

        
        outputStr 
+= endStr;    
        
        
return outputStr; 
    }


用法和参数含义均同前,注意省略号也占位置,算了长度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值