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

C# 依標點符號分行顯示文字

     編輯:關於C#

前言

將長文字依標點符號自動換行,是文字排版常見需求。本文示範使用 String.Split 分割字串,搭配換行符號重組的基本做法,並擴充支援多種標點、保留標點符號、HTML 輸出等進階功能。

基本實作:單一標點分割


using System;
using System.Windows.Forms;

public class TextFormatter
{
    public string SplitByPunctuation(string input, char punctuation)
    {
        if (string.IsNullOrEmpty(input))
            return input;
        
        string[] parts = input.Split(punctuation);
        string result = "";
        
        for (int i = 0; i < parts.Length; i++)
        {
            if (i == 0)
                result = parts[i];
            else
                result += "\n" + parts[i];
        }
        
        return result;
    }
}

改良版:保留標點符號


public string SplitByPunctuationKeep(string input, params char[] punctuations)
{
    if (string.IsNullOrEmpty(input))
        return input;
    
    // 使用正則表達式分割,但保留分隔符
    string pattern = $"([{Regex.Escape(new string(punctuations))}])";
    string[] parts = Regex.Split(input, pattern);
    
    var result = new StringBuilder();
    StringBuilder currentLine = new StringBuilder();
    
    foreach (string part in parts)
    {
        if (punctuations.Contains(part[0]))
        {
            currentLine.Append(part);
            result.AppendLine(currentLine.ToString());
            currentLine.Clear();
        }
        else
        {
            currentLine.Append(part);
        }
    }
    
    // 處理最後一行無標點結尾的情況
    if (currentLine.Length > 0)
        result.Append(currentLine);
    
    return result.ToString();
}

進階版:支援中英文標點、自訂換行邏輯


using System.Text.RegularExpressions;

public class AdvancedTextFormatter
{
    // 預設中文標點
    private static readonly char[] ChinesePunctuations = 
        { '。', '!', '?', ';', ':', '、', ',', '.' };
    
    // 預設英文標點
    private static readonly char[] EnglishPunctuations = 
        { '.', '!', '?', ';', ':', ',' };

    public string FormatText(string input, 
        char[] punctuations = null, 
        string lineBreak = "\n",
        bool trimLines = true,
        bool keepPunctuation = true)
    {
        if (string.IsNullOrEmpty(input))
            return input;
        
        punctuations ??= ChinesePunctuations.Concat(EnglishPunctuations).ToArray();
        
        if (keepPunctuation)
        {
            return SplitKeepPunctuation(input, punctuations, lineBreak, trimLines);
        }
        else
        {
            return SplitRemovePunctuation(input, punctuations, lineBreak, trimLines);
        }
    }

    private string SplitKeepPunctuation(string input, char[] punctuations, 
        string lineBreak, bool trim)
    {
        string punctuationPattern = Regex.Escape(new string(punctuations));
        string pattern = $"([{punctuationPattern}])";
        string[] parts = Regex.Split(input, pattern);
        
        var sb = new StringBuilder();
        var line = new StringBuilder();
        
        foreach (string part in parts)
        {
            if (part.Length == 1 && punctuations.Contains(part[0]))
            {
                line.Append(part);
                string lineText = trim ? line.ToString().Trim() : line.ToString();
                sb.Append(lineText).Append(lineBreak);
                line.Clear();
            }
            else
            {
                line.Append(part);
            }
        }
        
        // 最後一段
        if (line.Length > 0)
        {
            string lineText = trim ? line.ToString().Trim() : line.ToString();
            sb.Append(lineText);
        }
        
        return sb.ToString();
    }

    private string SplitRemovePunctuation(string input, char[] punctuations, 
        string lineBreak, bool trim)
    {
        string[] parts = input.Split(punctuations, StringSplitOptions.RemoveEmptyEntries);
        var sb = new StringBuilder();
        
        for (int i = 0; i < parts.Length; i++)
        {
            string lineText = trim ? parts[i].Trim() : parts[i];
            sb.Append(lineText);
            if (i < parts.Length - 1)
                sb.Append(lineBreak);
        }
        
        return sb.ToString();
    }
}

HTML 輸出版本


public string FormatForHtml(string input, char[] punctuations = null)
{
    string text = FormatText(input, punctuations, "
", true, true); // HTML 編碼防止 XSS return System.Web.HttpUtility.HtmlEncode(text).Replace("\n", "
"); }

WinForms / WPF 整合範例


// WinForms RichTextBox 顯示
private void DisplayFormattedText(string input)
{
    var formatter = new AdvancedTextFormatter();
    string formatted = formatter.FormatText(input);
    richTextBox1.Text = formatted;
}

// WPF TextBlock 顯示 (XAML 中使用 LineBreak)
private void DisplayInWpf(string input)
{
    var formatter = new AdvancedTextFormatter();
    string formatted = formatter.FormatText(input, lineBreak: "\n");
    
    // 或建立 Inline 集合
    textBlock1.Inlines.Clear();
    foreach (string line in formatted.Split('\n'))
    {
        textBlock1.Inlines.Add(new Run(line));
        textBlock1.Inlines.Add(new LineBreak());
    }
}

效能考量:大量文字處理


public string FormatLargeText(string input, char[] punctuations)
{
    // 使用 StringBuilder 避免字串連接產生大量暫存物件
    var sb = new StringBuilder(input.Length + 100); // 預估容量
    var line = new StringBuilder();
    
    foreach (char c in input)
    {
        line.Append(c);
        if (punctuations.Contains(c))
        {
            sb.AppendLine(line.ToString().Trim());
            line.Clear();
        }
    }
    
    if (line.Length > 0)
        sb.Append(line.ToString().Trim());
    
    return sb.ToString();
}

單元測試範例


[TestClass]
public class TextFormatterTests
{
    private AdvancedTextFormatter _formatter = new AdvancedTextFormatter();

    [TestMethod]
    public void TestChinesePunctuation()
    {
        string input = "你好世界。這是測試!結束。";
        string expected = "你好世界。\n這是測試!\n結束。";
        Assert.AreEqual(expected, _formatter.FormatText(input));
    }

    [TestMethod]
    public void TestMixedPunctuation()
    {
        string input = "Hello. World! 你好。";
        string expected = "Hello.\n World!\n 你好。";
        Assert.AreEqual(expected, _formatter.FormatText(input));
    }

    [TestMethod]
    public void TestNoPunctuation()
    {
        string input = "沒有標點符號";
        Assert.AreEqual(input, _formatter.FormatText(input));
    }

    [TestMethod]
    public void TestEmptyInput()
    {
        Assert.AreEqual("", _formatter.FormatText(""));
        Assert.AreEqual(null, _formatter.FormatText(null));
    }
}

常見標點符號分類

類別符號Unicode用途
中文句末。 ! ?U+3002 U+FF01 U+FF1F句子結束
中文句內、 , ; :U+3001 U+FF0C U+FF1B U+FF1A子句分隔
英文句末. ! ?U+002E U+0021 U+003F句子結束
英文句內, ; :U+002C U+003B U+003A子句分隔
特殊… — ~U+2026 U+2014 U+FF5E省略、連接、波浪

總結

依標點分行的核心是 Split 或 Regex.Split 配合 StringBuilder 重組。關鍵在於:是否保留標點、支援哪些標點集合、如何處理最後一段無標點文字。建議封裝為可配置的格式化類別,支援多種輸出格式(純文字、HTML、WPF Inlines),並針對大量文字優化記憶體使用。

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