You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#正则表达式问题:分割文本时完全排除前后数字

解决LINQPad中C#脚本分割页码与标题的问题

问题说明

在LINQPad中运行C#脚本,目标是将包含页码数字与标题的文本分割后生成XML格式目录。当前使用Regex.Split的正则表达式分割后,标题中仍包含页码数字(如“2 ALASKA”),希望分割后的标题完全排除数字(如“ALASKA”)。

原脚本

class Program
{
    static void Main()
    {
        string text = "Why Cruise? 2 ALASKA 4 The Canadian Rockies & Alaska 6 Alaska by Land & Sea 8 Fairmonts of Western Canada & Incredible Alaska 10 Alaska’s Wilderness, Glaciers & Culture 12 THE CARIBBEAN 14 Ultimate Caribbean 16 Orlando & the Caribbean 17 Tall Ship Sailing in the Grenadine Islands 18 Hidden Gems of the Caribbean 19";

        string[] textArr = Regex.Split(text, @"(?<=\s)(?=\d+(?!\d))");

        string re = "(?:^|(?<=\\s))\\d+(?=\\s|$)";

        MatchCollection numArr = Regex.Matches(text, re, RegexOptions.IgnoreCase);

        Console.WriteLine("<?xml version=\"1.0\" encoding=\"UTF-8\" ?><ols>");
        Console.WriteLine("<o><c><![CDATA[Front Page]]></c><p>1</p><l>1</l><ci></ci></o>");
        Console.WriteLine("<o><c><![CDATA[Contents]]></c><p>3</p><l>1</l><ci></ci></o>");
        Console.WriteLine("<o><c><![CDATA[Map]]></c><p>4</p><l>1</l><ci></ci></o>");

        for (int i = 0; i < textArr.Length-1; i++)
        {
            string pageTitle = textArr[i].Trim();
            string pageNumber = numArr[i].Value;
            Console.WriteLine("<o><c><![CDATA["+pageTitle+"]]></c><p>"+PageNo(pageNumber)+"</p><l>1</l><ci></ci></o>");
        }

        Console.WriteLine("</ols>");
    }
    
    static string PageNo(string num) {
        int pgno = int.Parse(num) + 2;
        return pgno.ToString();
    }
}

当前输出问题

生成的XML中,标题仍包含页码:

<?xml version="1.0" encoding="UTF-8" ?><ols>
<o><c><![CDATA[Front Page]]></c><p>1</p><l>1</l><ci></ci></o>
<o><c><![CDATA[Contents]]></c><p>3</p><l>1</l><ci></ci></o>
<o><c><![CDATA[Map]]></c><p>4</p><l>1</l><ci></ci></o>
<o><c><![CDATA[Why Cruise?]]></c><p>4</p><l>1</l><ci></ci></o>
<o><c><![CDATA[2 ALASKA]]></c><p>6</p><l>1</l><ci></ci></o>
<o><c><![CDATA[4 The Canadian Rockies & Alaska]]></c><p>8</p><l>1</l><ci></ci></o>
<o><c><![CDATA[6 Alaska by Land & Sea]]></c><p>10</p><l>1</l><ci></ci></o>
<o><c><![CDATA[8 Fairmonts of Western Canada & Incredible Alaska]]></c><p>12</p><l>1</l><ci></ci></o>
<o><c><![CDATA[10 Alaska’s Wilderness, Glaciers & Culture]]></c><p>14</p><l>1</l><ci></ci></o>
<o><c><![CDATA[12 THE CARIBBEAN]]></c><p>16</p><l>1</l><ci></ci></o>
<o><c><![CDATA[14 Ultimate Caribbean]]></c><p>18</p><l>1</l><ci></ci></o>
<o><c><![CDATA[16 Orlando & the Caribbean]]></c><p>19</p><l>1</l><ci></ci></o>
<o><c><![CDATA[17 Tall Ship Sailing in the Grenadine Islands]]></c><p>20</p><l>1</l><ci></ci></o>
<o><c><![CDATA[18 Hidden Gems of the Caribbean]]></c><p>21</p><l>1</l><ci></ci></o>
</ols>

解决方案

换用正则匹配捕获组直接提取页码和纯标题,避免拆分后处理的麻烦。核心思路是用正则一次性匹配出每个“页码+标题”的组合,同时单独处理开头无页码的“Why Cruise?”。

修改后的脚本

class Program
{
    static void Main()
    {
        string text = "Why Cruise? 2 ALASKA 4 The Canadian Rockies & Alaska 6 Alaska by Land & Sea 8 Fairmonts of Western Canada & Incredible Alaska 10 Alaska’s Wilderness, Glaciers & Culture 12 THE CARIBBEAN 14 Ultimate Caribbean 16 Orlando & the Caribbean 17 Tall Ship Sailing in the Grenadine Islands 18 Hidden Gems of the Caribbean 19";

        // 先处理开头无页码的条目
        string firstTitle = "Why Cruise?";
        // 匹配所有页码+标题的组合:捕获组1是页码,捕获组2是标题
        var matches = Regex.Matches(text, @"\s(\d+)\s+([^\d]+?)(?=\s+\d+|$)", RegexOptions.Singleline);

        Console.WriteLine("<?xml version=\"1.0\" encoding=\"UTF-8\" ?><ols>");
        Console.WriteLine("<o><c><![CDATA[Front Page]]></c><p>1</p><l>1</l><ci></ci></o>");
        Console.WriteLine("<o><c><![CDATA[Contents]]></c><p>3</p><l>1</l><ci></ci></o>");
        Console.WriteLine("<o><c><![CDATA[Map]]></c><p>4</p><l>1</l><ci></ci></o>");

        // 输出第一个无页码的标题,对应页码2(原文本中它后面的第一个页码是2)
        Console.WriteLine($"<o><c><![CDATA[{firstTitle}]]></c><p>{PageNo("2")}</p><l>1</l><ci></ci></o>");

        // 遍历匹配结果,输出每个标题和页码
        foreach (Match match in matches)
        {
            string pageNumber = match.Groups[1].Value.Trim();
            string pageTitle = match.Groups[2].Value.Trim();
            Console.WriteLine($"<o><c><![CDATA[{pageTitle}]]></c><p>{PageNo(pageNumber)}</p><l>1</l><ci></ci></o>");
        }

        Console.WriteLine("</ols>");
    }
    
    static string PageNo(string num) {
        int pgno = int.Parse(num) + 2;
        return pgno.ToString();
    }
}

关键说明

  1. 正则表达式:\s(\d+)\s+([^\d]+?)(?=\s+\d+|$)
    • \s(\d+):匹配空格+页码,捕获页码到组1
    • \s+([^\d]+?):匹配空格+标题(非数字内容),捕获标题到组2,+?是非贪婪匹配,避免过度匹配
    • (?=\s+\d+|$):正向预查,确保后面是空格+下一个页码或文本结尾
  2. 单独处理开头条目:原文本开头的“Why Cruise?”没有前置页码,单独提取后对应后续第一个页码2
  3. 输出XML:直接用捕获的纯标题和页码生成节点,确保标题不含数字

修改后输出示例

<?xml version="1.0" encoding="UTF-8" ?><ols>
<o><c><![CDATA[Front Page]]></c><p>1</p><l>1</l><ci></ci></o>
<o><c><![CDATA[Contents]]></c><p>3</p><l>1</l><ci></ci></o>
<o><c><![CDATA[Map]]></c><p>4</p><l>1</l><ci></ci></o>
<o><c><![CDATA[Why Cruise?]]></c><p>4</p><l>1</l><ci></ci></o>
<o><c><![CDATA[ALASKA]]></c><p>6</p><l>1</l><ci></ci></o>
<o><c><![CDATA[The Canadian Rockies & Alaska]]></c><p>8</p><l>1</l><ci></ci></o>
<o><c><![CDATA[Alaska by Land & Sea]]></c><p>10</p><l>1</l><ci></ci></o>
<o><c><![CDATA[Fairmonts of Western Canada & Incredible Alaska]]></c><p>12</p><l>1</l><ci></ci></o>
<o><c><![CDATA[Alaska’s Wilderness, Glaciers & Culture]]></c><p>14</p><l>1</l><ci></ci></o>
<o><c><![CDATA[THE CARIBBEAN]]></c><p>16</p><l>1</l><ci></ci></o>
<o><c><![CDATA[Ultimate Caribbean]]></c><p>18</p><l>1</l><ci></ci></o>
<o><c><![CDATA[Orlando & the Caribbean]]></c><p>19</p><l>1</l><ci></ci></o>
<o><c><![CDATA[Tall Ship Sailing in the Grenadine Islands]]></c><p>20</p><l>1</l><ci></ci></o>
<o><c><![CDATA[Hidden Gems of the Caribbean]]></c><p>21</p><l>1</l><ci></ci></o>
</ols>

内容的提问来源于stack exchange,提问作者Mshah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 04:47:23