【问题标题】:Regex to break a line at the last comma before a certain length / number of characters正则表达式在一定长度/字符数之前的最后一个逗号处换行
【发布时间】:2021-02-26 11:21:28
【问题描述】:

有人将此作为另一个无关问题 (C# Regex split by multiple closing brackets sets) 的补充,因此我将其作为单独的问题添加:

我有很多行,如果其中一行超过 50 个字符,我想在 50 个字符之前的最后一个逗号 (,) 处拆分这些行。

示例输入:

AND ( AUART IN ( 'PM01', 'PM02', 'PM03' ) )
AND ( AUART IN ( 'PM01', 'PM02', 'PM03', 'PM10', 'PM99', 'PM59' ) )
AND ( AUART IN ( 'PM01', 'PM01232132132', 'PM03' ) )

预期输出:

AND ( AUART IN ( 'PM01', 'PM02', 'PM03' ) )
AND ( AUART IN ( 'PM01', 'PM02', 'PM03', 'PM10',
 'PM99', 'PM59' ) )
AND ( AUART IN ( 'PM01', 'PM01232132132',
 'PM03' ) )

【问题讨论】:

  • (.{50},) 替换为$1\r\n See it here
  • 那行不通。如您的示例所示,生成的拆分将超过 50 个字符。查看预期输出。
  • 是的。我的马虎;)将其更改为^(?=.{50})(.{1,49},)Here...。但这基本上就是你已经得到的答案:P

标签: c# regex


【解决方案1】:

您也可以使用不带捕获组的模式和断言字符串开头或逗号的后向。

然后在右边断言 50 个字符并匹配 1-49 个字符,后跟一个逗号。

在替换中使用完整匹配,后跟换行符$0\n

(?<=^|,)(?=.{50}).{1,49},

Regex demo | C# demo

List<string> strings = new List<string>()
{
    "AND ( AUART IN ( 'PM01', 'PM02', 'PM03' ) )",
    "AND ( AUART IN ( 'PM01', 'PM02', 'PM03', 'PM10', 'PM99', 'PM59' ) )",
    "AND ( AUART IN ( 'PM01', 'PM01232132132', 'PM03' ) )",
    "AND ( AUART IN ( 'PM0654654654654654654654654654651', 'PM02' ) )",
    "AND ( AUART IN ( 'PM01', 'PM02', 'PM03', 'PM04', 'PM11', 'PM12', 'PM13', 'PM14', 'PM15', 'PM16', 'PM21', 'PM22', 'PM23', 'PM24', 'PM25', 'PM31' ) )"
};
var regex = new Regex(@"(?<=^|,)(?=.{50}).{1,49},");

foreach (String s in strings)
{
    Console.WriteLine(regex.Replace(s, "$0\n"));
}

输出

AND ( AUART IN ( 'PM01', 'PM02', 'PM03' ) )
AND ( AUART IN ( 'PM01', 'PM02', 'PM03', 'PM10',
 'PM99', 'PM59' ) )
AND ( AUART IN ( 'PM01', 'PM01232132132',
 'PM03' ) )
AND ( AUART IN ( 'PM0654654654654654654654654654651', 'PM02' ) )
AND ( AUART IN ( 'PM01', 'PM02', 'PM03', 'PM04',
 'PM11', 'PM12', 'PM13', 'PM14', 'PM15', 'PM16',
 'PM21', 'PM22', 'PM23', 'PM24', 'PM25',
 'PM31' ) )

【讨论】:

  • 太好了,这比我的效果更好,因为它可以一次替换整个字符串!为了完整起见,您还可以使用\G 断言字符串的开头或上一个匹配的结尾:\G(?=.{50}).{1,49},。干杯。
【解决方案2】:

如果您的正则表达式长度超过 50 个字符,您可以使用匹配整行的肯定前瞻断言开始您的正则表达式,然后添加否定后瞻断言以确保您要匹配的逗号前少于 50 个字符:

(?=.{50})(.*)(?&lt;!.{50})(,)

然后你找到了你想要分割的逗号,例如替换为逗号和换行符。

完整示例:

using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      string pattern = @"(?=.{50})(.*)(?<!.{50})(,)";
      string replacement = "$1,\n";
      List<string> inputs = new List<string>();
      inputs.Add("AND ( AUART IN ( 'PM01', 'PM02', 'PM03' ) )"); // shorter than 50 chars
      inputs.Add("AND ( AUART IN ( 'PM01', 'PM02', 'PM03', 'PM10', 'PM99', 'PM59' ) )");
      inputs.Add("AND ( AUART IN ( 'PM01', 'PM01232132132', 'PM03' ) )");
      inputs.Add("AND ( AUART IN ( 'PM0654654654654654654654654654651', 'PM02' ) )"); // first comma appearing later than character 50
     
      foreach (string input in inputs)
      {
          string result = Regex.Replace(input, pattern, replacement);
          Console.WriteLine(result);
      }
   }
}

请注意,这有一些限制:

  1. 如果引号 (') 中有逗号,则正则表达式将匹配,这可能是也可能不是您想要的。
  2. 如果第一个逗号出现在位置 50 之后,正则表达式显然会不匹配
  3. 如果该行超过 ~100 个字符,第二部分将再次超过 50 个字符,我猜这不是你想要的

最后一点可以通过在捕获组中捕获剩余部分并在剩余部分超过 50 个字符时使用递归再次应用正则表达式来解决:

using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      List<string> inputs = new List<string>();
      inputs.Add("AND ( AUART IN ( 'PM01', 'PM02', 'PM03' ) )"); // shorter than 50 chars
      inputs.Add("AND ( AUART IN ( 'PM01', 'PM02', 'PM03', 'PM10', 'PM99', 'PM59' ) )");
      inputs.Add("AND ( AUART IN ( 'PM01', 'PM01232132132', 'PM03' ) )");
      inputs.Add("AND ( AUART IN ( 'PM0654654654654654654654654654651', 'PM02' ) )"); // first comma appearing later than character 50
      inputs.Add("AND ( AUART IN ( 'PM01', 'PM02', 'PM03', 'PM04', 'PM11', 'PM12', 'PM13', 'PM14', 'PM15', 'PM16', 'PM21', 'PM22', 'PM23', 'PM24', 'PM25', 'PM31' ) )"); // string longer than 100 chars, i.e. the remainder needs to be processed again
      List<string> results = new List<string>();
       
      var regex = new Regex(@"((?=.{50}).*(?<!.{50}),)(.*)");
    
      foreach (string input in inputs)
      {
          string str = input;
          while(!String.IsNullOrEmpty(str)) {
             var match = regex.Match(str);
             if (match.Success) {
                 results.Add(match.Groups[1].Value);         
                 str = match.Groups[2].Value;
             } else {
                 results.Add(str);
                 break;
             }
          }
      }
      Console.WriteLine(String.Join("\n", results));
   }
}

结果:

AND ( AUART IN ( 'PM01', 'PM02', 'PM03' ) )
AND ( AUART IN ( 'PM01', 'PM02', 'PM03', 'PM10',
 'PM99', 'PM59' ) )
AND ( AUART IN ( 'PM01', 'PM01232132132',
 'PM03' ) )
AND ( AUART IN ( 'PM0654654654654654654654654654651', 'PM02' ) )
AND ( AUART IN ( 'PM01', 'PM02', 'PM03', 'PM04',
 'PM11', 'PM12', 'PM13', 'PM14', 'PM15', 'PM16',
 'PM21', 'PM22', 'PM23', 'PM24', 'PM25',
 'PM31' ) )

为了解决第二点,您可以考虑使用逗号, 和空格\s 而不是仅使用逗号(如果在您的应用场景中可能的话)。正则表达式为((?=.{50}).*(?&lt;!.{50})[\s,])(.*)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-06
    • 2021-10-12
    • 1970-01-01
    • 2015-07-26
    • 2019-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多