C# 中按字节数截取字符串

在C#语言中,按字符数截取字符串可采用String类的SubString方法实现,但很多情况下,我们需要按字节数截取字符串。

举例来说,现有一行文字,屏幕上需要展示的界面宽度有限,但文字的总长度可能比界面的宽度要长,这就导致了屏幕上显示不下所有的字,为解决这一问题,有一个办法是只显示字符串开始的部分,然后将后面显示不下的部分替换为省略号(...)。

但是,因为全角字符和半角字符的长度是不一样的,我们不能按字符数截取字符串。如下图所示,字符串“1234567890”和“一二三四五六七八九〇”,长度都是10,但后者占据的实际长度是前者的两倍!(如果采用的不是等宽字体,那长度的偏差会千奇百怪,本文中的DEMO采用的都是Windows控制台默认的点阵字体)

一个半角字符占一个字节,一个全角字符占两个字节,而全角字符在显示上又是半角字符的两倍。 如果我们可以按字节数截取字符串,就可以保证截取字符串的长度了。

我先实现了下面这个函数,对字符串进行裁剪。

/// <summary>
/// 裁减字符串 - 直接裁减
/// </summary>
/// <param name="originalText">被裁减字符串</param>
/// <param name="bytesAfterCut">需保留的字节数</param>
/// <returns></returns>
public static string GetTreatedText(string originalText, int bytesAfterCut)
{
    string treatedText = originalText;
    byte[] val = Encoding.Default.GetBytes(originalText);
    if (val.Length > bytesAfterCut)
    {
        treatedText = Encoding.Default.GetString(val, 0, bytesAfterCut) + "...";
    }
    return treatedText;
}

但这个方法有一个致命的漏洞,即全角字符占据两个字节,如果被裁剪字符串时,下剪的位置恰好将一个全角字符减成两半,那显示出来的字符串的最后面会出现一个问号(?)。

如下面的程序,对字符串“你好吗”进行裁剪,要求保留5个字节。但“吗”字被保留了半个字节后,就无法正确显示了。

因此,我们需要对裁剪方法做一下优化,代码如下:

/// <summary>
/// 裁减字符串 - 优化版 liwh - 20160523
/// </summary>
/// <param name="originalText">被裁减字符串</param>
/// <param name="bytesAfterCut">需保留的字节数</param>
/// <returns></returns>
public static string GetOptimizedText(string originalText, int bytesAfterCut)
{
    string optimizedText = originalText;
    byte[] val = Encoding.Default.GetBytes(originalText);
    if (val.Length > bytesAfterCut)
    {
        int left = bytesAfterCut / 2;
        int right = bytesAfterCut;
        left = left > originalText.Length ? originalText.Length : left;
        right = right > originalText.Length ? originalText.Length : right;
        while (left < right - 1)
        {
            int mid = (left + right) / 2;
            if (Encoding.Default.GetBytes(originalText.Substring(0, mid)).Length > 
                bytesAfterCut)
            {
                right = mid;
            }
            else
            {
                left = mid;
            }
        }
        byte[] rightVal = Encoding.Default.GetBytes(originalText.Substring(0, right));
        if (rightVal.Length == bytesAfterCut)
        {
            optimizedText = originalText.Substring(0, right) + "...";
        }
        else
        {
            optimizedText = originalText.Substring(0, left) + "...";
        }
    }
    return optimizedText;
}

如果发现修剪后会导致最后一个全角字符不能正确显示,则应将那个全角字符整个抛弃。如下图所示,“你好吗”经裁剪后,会变为“你好”,只保留了4个字节的内容。

最后补充说明下:本文中描述的场景中,都是从第0字节的情况,截取指定字节数的内容。其他应用场景需做适当修改,但思路大体一致。

END

转载于:https://my.oschina.net/Tsybius2014/blog/680010

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值