Web 開發中常需在 GridView、Repeater、ListView 等控制項顯示不定長度文字,超過寬度需自動換行或截斷加上省略號 (`...`)。本文提供兩個實用的靜態方法:`CutStr` (純換行) 與 `CutStr` 多載 (長度限制 + 省略號),並分析其邏輯、效能與現代 CSS 替代方案。
///
/// 將字串每 len 字元換行,不限制總長度
///
/// 原始字串
/// 每行字元數
/// 含換行字元的字串
public static string CutStr(string str, int len)
{
if (string.IsNullOrEmpty(str) || len <= 0) return str;
var sb = new System.Text.StringBuilder();
for (int i = 0; i < str.Length; i += len)
{
int remaining = str.Length - i;
int take = Math.Min(len, remaining);
sb.Append(str.Substring(i, take));
if (i + take < str.Length) sb.Append("
"); // HTML 換行
}
return sb.ToString();
}
///
/// 截取字串至最大長度,超過加省略號,並每 len 字元換行
///
/// 原始字串
/// 每行字元數
/// 最大輸出長度 (含省略號)
/// 處理後字串
public static string CutStr(string str, int len, int max)
{
if (string.IsNullOrEmpty(str) || len <= 0 || max <= 0) return str;
// 先截取至最大長度
if (str.Length > max)
{
str = str.Substring(0, max - 3) + "..."; // 預留 3 字元給省略號
}
// 再依 len 換行
var sb = new System.Text.StringBuilder();
for (int i = 0; i < str.Length; i += len)
{
int remaining = str.Length - i;
int take = Math.Min(len, remaining);
sb.Append(str.Substring(i, take));
if (i + take < str.Length) sb.Append("
");
}
return sb.ToString();
}
string longText = "這是一段很長的文字內容,用來示範自動換行與截斷省略號的效果。";
// 每 10 字元換行
lbl1.Text = CutStr(longText, 10);
// 輸出:這是一段很長
的文字內容,用
來示範自動換
行與截斷省略
號的效果。
// 最大 30 字元,每 10 字元換行
lbl2.Text = CutStr(longText, 10, 30);
// 輸出:這是一段很長的文
字內容,用來示範...
| 原始碼特徵 | 問題 | 改進版處理 |
|---|---|---|
| 雙重迴圈、模運算判斷換行 | 邏輯複雜、難閱讀、效能較差 | 單一迴圈 `i += len` 步進,清晰高效 |
| 直接回傳 ` ` | 耦合 HTML、無法用於純文字/JSON | 參數化 `separator` (預設 ` `),支援 `\n`、`Environment.NewLine` |
| 省略號硬編碼 `...` | 無法自訂 (如 `…`、`[更多]`) | 參數化 `ellipsis` |
| 未處理 HTML 標籤截斷 | 可能切斷 ``、`` 導致版面崩壞 | 建議搭配 `HtmlAgilityPack` 或 `HttpUtility.HtmlEncode` 先編碼 |
| 中英文混排視覺寬度不一 | 字元數 ≠ 顯示寬度 | 進階版可依 `TextRenderer.MeasureText` 或 CSS `text-overflow` 處理 |
public static string CutStr(
string str,
int lineLength,
int? maxLength = null,
string lineSeparator = "
",
string ellipsis = "...",
bool htmlEncode = true)
{
if (string.IsNullOrEmpty(str) || lineLength <= 0) return str;
if (htmlEncode) str = System.Web.HttpUtility.HtmlEncode(str);
if (maxLength.HasValue && str.Length > maxLength.Value)
{
int cutLen = Math.Max(0, maxLength.Value - ellipsis.Length);
str = str.Substring(0, cutLen) + ellipsis;
}
var sb = new System.Text.StringBuilder();
for (int i = 0; i < str.Length; i += lineLength)
{
int take = Math.Min(lineLength, str.Length - i);
sb.Append(str.Substring(i, take));
if (i + take < str.Length) sb.Append(lineSeparator);
}
return sb.ToString();
}
.text-truncate {
display: -webkit-box;
-webkit-line-clamp: 3; /* 顯示 3 行 */
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
word-break: break-all; /* 中文強制斷字 */
}
/* 單行省略 */
.single-line {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
<asp:Label ID="lblDesc" runat="server" CssClass="text-truncate"
Text='<%# Eval("Description") %>' />
| 場景 | 推薦方案 |
|---|---|
| 純文字郵件/簡訊/報表匯出 | 伺服器端 `CutStr` (無 CSS 支援) |
| GridView/Repeater 一般文字欄位 | CSS `text-overflow` + `line-clamp` |
| 含 HTML 標籤的富文本摘要 | 伺服器端 `HtmlAgilityPack` 截斷 + CSS 雙重保險 |
| 多語言/混排/精確視覺寬度 | Canvas `measureText` / JavaScript 客戶端計算 |
| PDF/列印輸出 | 伺服器端精確排版 (iTextSharp/QuestPDF) |
字串截取看似瑣碎,卻關係到資料呈現品質、使用者體驗、甚至安全性 (防 XSS)。掌握伺服器端邏輯與客戶端 CSS 的分工協作,並根據輸出媒介選擇適當策略,是資深 Web 開發者的基本功。