C#判斷字串的顯示寬度

吳俊城發表於2023-11-08

C#判斷字串的顯示寬度

起因:

公司有一個使用專案使用HTML轉換為PDF,其中有一個表格,表格的最後一列中的單元格,其字串超長後會被丟棄,而不是換行到下一行展示(HtmlToPdf渲染引擎導致的,沒辦法更改)

解決方案:

根據字串長度手動新增<br/>換行

var source = "ABCD";

if (GetLength(source)>2)
{
    source = source.Insert(2,"<br/>");
}

Console.WriteLine(source);
// 輸出AB<br/>CD

int GetLength(string src)
{
    return src.Length;
}

出現了一個BUG:

當原始內容中存在中文時,中文字元的顯示寬度大於英文字元的寬度,按照字串中的字元數進行處理,並不準確

/*
* 中文:中文<br/>CD
* 英文:AB<br/>CD
*/

原因分析:

在文字的顯示中,有全形和半形的區別

全形:指一個字元佔用兩個標準字元位置的狀態。

半形:指一個字元佔用一個標準字元位置的狀態。

嘗試解決:

字元編碼:最早的字元編碼為Ascii碼,只考慮了英文語種使用者,後來隨著計算機的普及,有了其他編碼,比如GB2312、UTF8等,不止包含英文的字元編碼,但是這些編碼都對Ascii碼進行了相容

沒有細心求證的結論:Ascii碼對應的是半形,中文擴充套件部分是全形展示,半形顯示寬度為全形的一半(這結論是我猜的,沒有求證,如果不對還請提出批評指正)

透過上面猜測的結論,可以先對每個字元判斷是不是Ascii字元來決定當前是全形還是半形


var source = "ABCD";
var index =InserAtDisplayWidth(2,source);
if (index!=-1)
{
    source = source.Insert(index,"<br/>");
}
// AB<br/>CD
Console.WriteLine(source);

var source2 = "中文CD"; 
var index2 =InserAtDisplayWidth(2,source2);
if (index2!=-1)
{
    source2 = source2.Insert(index2,"<br/>");
}
// 中<br/>文CD
Console.WriteLine(source2);



int InserAtDisplayWidth(int inserAtDisplayWidth, string source){
    int now =0;
    for (int i = 0; i < source.Length; i++)
    {
        if( char.IsAscii(source[i])){
            // 半形佔一個顯示寬度
            now +=1;
        }else{
            // 全形佔兩個顯示寬度
            now +=2;
        };

        if (now>inserAtDisplayWidth)
        {
            return i;
        }
    }
    return -1;
}

透過對字元的判斷,更加準確的匹配了分隔的位置,既避免了無效的空白區域,又避免了過長的字串溢位導致看不到內容

/*
* AB<br/>CD
* 中<br/>文CD
*/

相關文章