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(); } }
关键说明
- 正则表达式:
\s(\d+)\s+([^\d]+?)(?=\s+\d+|$)\s(\d+):匹配空格+页码,捕获页码到组1\s+([^\d]+?):匹配空格+标题(非数字内容),捕获标题到组2,+?是非贪婪匹配,避免过度匹配(?=\s+\d+|$):正向预查,确保后面是空格+下一个页码或文本结尾
- 单独处理开头条目:原文本开头的“Why Cruise?”没有前置页码,单独提取后对应后续第一个页码2
- 输出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
相关产品推荐
相关产品推荐

