首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# 截取中英混合字串:依位元組長度保留完整字元

     編輯:關於C語言

問題描述

在文章列表、摘要顯示等情境中,常需截取指定長度的字串並附加「...」。挑戰在於:中文字元佔 2 個位元組(UTF-8 下為 3 位元組),英文佔 1 個位元組。若單純用 Substring 按字元數截取,會導致顯示寬度不一;若按位元組截取,可能將中文字元切成兩半產生亂碼。

需求

  • 輸入:「中國人要啊abc呀~」,指定位元組長度 8(不含「...」)。
  • 輸出:「中國人要...」(中文 4 字 = 8 位元組)。
  • 輸入:「1中國人23456abc呀~」,同樣 8 位元組。
  • 輸出:「1中國人2...」(1 個英文 + 3 個中文 + 1 個英文 = 1+6+1=8 位元組)。

解決方案:以 Regex 計算視覺寬度

利用正則將中文字元替換為雙字元(如 "zz"),再量測字串長度,即可得到「視覺位元組長度」。

using System.Text.RegularExpressions;

public static class StringHelper
{
    /// 
    /// 截取中英混合字串,依視覺位元組長度(中文算 2,英文算 1)截取,並附加省略號。
    /// 
    /// 原始字串
    /// 目標位元組長度(不含省略號)
    /// 截取後字串,若未超長則回傳原字串
    public static string TruncateByVisualLength(string input, int byteLength)
    {
        if (string.IsNullOrEmpty(input)) return input;

        // 計算視覺長度:中文->zz (長度2),其他保持
        string visual = Regex.Replace(input, "[\u4e00-\u9fa5]", "zz");
        if (visual.Length <= byteLength)
            return input; // 未超長

        // 從尾端往前嘗試截取
        for (int i = input.Length; i >= 0; i--)
        {
            string candidate = input.Substring(0, i);
            string candVisual = Regex.Replace(candidate, "[\u4e00-\u9fa5]", "zz");
            if (candVisual.Length <= byteLength - 3) // 預留「...」3個位元組
            {
                return candidate + "...";
            }
        }

        return "..."; // 極端情況
    }
}

使用範例

string s1 = "中國人要啊abc呀~";
string s2 = "1中國人23456abc呀~";

Console.WriteLine(StringHelper.TruncateByVisualLength(s1, 8)); // 中國人要...
Console.WriteLine(StringHelper.TruncateByVisualLength(s2, 8)); // 1中國人2...

進階:支援 Unicode 補充平面與 Emoji

上述正則 [\u4e00-\u9fa5] 僅涵蓋基本中日韓統一表意文字。若需支援擴展區(如 𠮷 U+20BB7)或 Emoji,建議改用 StringInfo 或 Rune(.NET Core 3.0+)逐字元計算:

public static string TruncateByVisualLengthAdvanced(string input, int byteLength)
{
    if (string.IsNullOrEmpty(input)) return input;

    int visualLen = 0;
    int charIndex = 0;
    foreach (Rune rune in input.EnumerateRunes())
    {
        // 簡易判斷:東亞寬字元視為 2,其餘為 1
        int w = (rune.Value >= 0x4E00 && rune.Value <= 0x9FFF) || // CJK 統一表意文字
                (rune.Value >= 0x3400 && rune.Value <= 0x4DBF) || // CJK 擴展 A
                (rune.Value >= 0x20000 && rune.Value <= 0x2FFFF)  // CJK 擴展 B~F
                ? 2 : 1;

        if (visualLen + w > byteLength - 3) break;
        visualLen += w;
        charIndex += rune.Utf16SequenceLength;
    }

    if (charIndex >= input.Length) return input;
    return input.Substring(0, charIndex) + "...";
}

結語

中英混合字串截取的核心在於視覺寬度計算。Regex 替換法簡單易懂,適合傳統 .NET Framework 專案;新專案建議使用 Rune 逐字元處理,支援完整 Unicode 並效能更佳。實務上應根據專案框架版本與字元集需求選擇適當實作。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved