傳統按字元數分頁在 HTML 內容(含圖片、標籤)前失效。本文提出基於**視覺行數預測**的分頁演算法,處理 <br>、<img> 等標籤,精確控制每頁行數。
<p>、<div> 等區塊標籤,保留 <br>、<img>。<br> 為主要分隔,計算文字行數:行數 = 字元數 / 每行字元數(不足半行算一行)。<img> 依 height 屬性換算行數(預設 400px = 16 行)。private static List<string> HtmlLineTest(ref string content, int pageSize = 30, int charsPerLine = 50)
{
var pages = new List<string>();
int lineCount = 0, pageLineCount = 0;
var sb = new StringBuilder();
// 1. 清理標籤
content = Regex.Replace(content, "<p[^>]*>", "", RegexOptions.IgnoreCase);
content = Regex.Replace(content, "<div[^>]*>", "", RegexOptions.IgnoreCase);
content = Regex.Replace(content, "</p>", "<br />", RegexOptions.IgnoreCase);
content = Regex.Replace(content, "</div>", "", RegexOptions.IgnoreCase);
// 2. 逐標籤處理
var matches = Regex.Matches(content, "<br\\s*/?>|<img[^>]+>", RegexOptions.IgnoreCase);
int lastIdx = 0;
foreach (Match m in matches)
{
string segment = content.Substring(lastIdx, m.Index - lastIdx);
if (!string.IsNullOrEmpty(segment))
{
sb.Append(segment);
int lines = Math.Max(1, (segment.Length + charsPerLine - 1) / charsPerLine);
lineCount += lines; pageLineCount += lines;
}
if (m.Value.StartsWith("<br"))
{
sb.Append("<br />");
lineCount++; pageLineCount++; // br 佔一行
}
else // img
{
sb.Append(m.Value).Append("<br />");
int imgLines = 16; // 預設
var hMatch = Regex.Match(m.Value, @"height\s*[:=]\s*['"]?(\d+)");
if (hMatch.Success) imgLines = Math.Max(1, int.Parse(hMatch.Groups[1].Value) / 25);
lineCount += imgLines; pageLineCount += imgLines;
}
if (pageLineCount >= pageSize)
{
pages.Add(sb.ToString());
sb.Clear();
pageLineCount = 0;
}
lastIdx = m.Index + m.Length;
}
// 3. 剩餘內容
if (lastIdx < content.Length) sb.Append(content.Substring(lastIdx));
if (sb.Length > 0) pages.Add(sb.ToString());
return pages;
}
適用於 CMS 文章閱讀、電子書閱讀器、列印預覽等場景。