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

C# 字串依位元組長度截取:解決中英混排顯示寬度不一問題

     編輯:關於C語言

問題背景

中文字元在 DBCS 編碼 (Big5/CP950) 佔 2 位元組,英文佔 1 位元組。直接用 Substring(0, n) 截取字元數會導致視覺寬度不一。需依「位元組長度」截取並補上省略號。

實作:CutStringByByteLength


using System;
using System.Text;

public static class StringExtensions
{
    /// 
    /// 依指定編碼的位元組長度截取字串,超長時附加省略號
    /// 
    public static string CutByByteLength(this string input, int maxBytes, Encoding encoding = null, string ellipsis = "…")
    {
        if (string.IsNullOrEmpty(input)) return input;
        encoding ??= Encoding.Default; // 系統預設編碼 (中文環境為 CP950)

        byte[] bytes = encoding.GetBytes(input);
        if (bytes.Length <= maxBytes) return input;

        // 截取位元組陣列並轉回字串 (可能截斷多位元組字元,需處理)
        byte[] truncated = new byte[maxBytes];
        Array.Copy(bytes, truncated, maxBytes);

        // 嘗試解碼,遇到無效位元組序列會產生替換字元 '?'
        string result = encoding.GetString(truncated);

        // 移除結尾可能的替換字元 (半個中文字元)
        if (result.EndsWith("?"))
            result = result.TrimEnd('?');

        return result + ellipsis;
    }

    /// 
    /// 更精確版:逐字元檢查累積位元組長度,避免截斷多位元組字元
    /// 
    public static string CutByByteLengthPrecise(this string input, int maxBytes, Encoding encoding = null, string ellipsis = "…")
    {
        if (string.IsNullOrEmpty(input)) return input;
        encoding ??= Encoding.Default;

        int currentBytes = 0;
        int charCount = 0;
        foreach (char c in input)
        {
            int charBytes = encoding.GetByteCount(new char[] { c });
            if (currentBytes + charBytes > maxBytes) break;
            currentBytes += charBytes;
            charCount++;
        }

        if (charCount >= input.Length) return input;
        return input.Substring(0, charCount) + ellipsis;
    }
}

使用範例


string s = "Hello 世界 123";
Console.WriteLine(s.CutByByteLength(10));        // "Hello 世…" (預設編碼)
Console.WriteLine(s.CutByByteLengthPrecise(10)); // "Hello 世…" (精確不截斷)

string utf8 = "Hello 世界";
Console.WriteLine(utf8.CutByByteLength(10, Encoding.UTF8)); // "Hello 世…" (UTF-8 中文佔3bytes)

編碼選擇指南

場景建議編碼中文位元組數
WinForms/WebForms 顯示寬度 (搭配 Monospace 字體)Encoding.Default (CP950/Big5)2
網頁前端 (UTF-8 頁面)Encoding.UTF83
資料庫欄位長度驗證 (VARCHAR BYTE)對應資料庫編碼視編碼而定

進階:取得字串顯示寬度 (像素)


using System.Drawing;

public static int GetTextWidth(string text, Font font)
{
    using (var bmp = new Bitmap(1, 1))
    using (var g = Graphics.FromImage(bmp))
    {
        return (int)g.MeasureString(text, font).Width;
    }
}

// 依像素寬度截取
public static string CutByPixelWidth(string text, Font font, int maxWidth, string ellipsis = "…")
{
    if (GetTextWidth(text, font) <= maxWidth) return text;
    int low = 0, high = text.Length;
    while (low < high)
    {
        int mid = (low + high + 1) / 2;
        if (GetTextWidth(text.Substring(0, mid), font) <= maxWidth) low = mid;
        else high = mid - 1;
    }
    return text.Substring(0, low) + ellipsis;
}

總結

  • 簡單需求用 CutByByteLength (位元組截取 + 解碼)
  • 嚴謹需求用 CutByByteLengthPrecise (逐字元累積位元組數)
  • UI 顯示建議直接量測像素寬度 Graphics.MeasureString
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved