正则表达式 - 忽略空格

Posted

技术标签:

【中文标题】正则表达式 - 忽略空格【英文标题】:Regex - Ignore the white spaces 【发布时间】:2021-09-13 23:49:12 【问题描述】:

我有一个正则表达式:

Regex.Match(result, @"\bTop Rate\b.*?\s*\s*([\d,\.]+)", RegexOptions.IgnoreCase);

然后解析成int

topRate = int.Parse(topRateMatch.Groups[1].Value, System.Globalization.NumberStyles.AllowThousands);

示例)

Top Rate: 888,888
Output: 888888

通过使用我当前的正则表达式,我得到了 int 输出。 但是,我注意到当数字之间有空格时 例如,

Top Rate: 8         88,888

我只得到 8 分。有没有办法忽略数字之间/最高评分字母之后可能存在或不存在的任何空格?

示例)

Top Rate:                       8                      88,888
Expected output: 888888

Top Rate:                       8     88,888
Expected output: 888888

Top Rate: 8                      88,888
Expected output: 888888

Top Rate: 8 8 8,888
Expected output: 888888

Top Rate: 888,          8  88
Expected output: 888888

【问题讨论】:

中间块(带有->)是什么意思?输入的规则是什么?给我们一些应该和不应该匹配的例子(以及为什么) 我会使用一种天真的解决方案,首先删除所有空格,然后再应用正则表达式来保持理智。 @Flydog57 这没什么意思。我只是想解释 888,888 ->(等于)888888 @MarkSouls 嗯嗯好的。如果可能的话,我试图添加 \s* 以使其工作。 @davis 如果你知道空格的位置就可以了,否则我怀疑它会变得相当复杂。 【参考方案1】:

首先,在匹配和捕获数字时不能跳过或省略空格,只能通过在给定字符串后提取多个匹配项来做到这一点。但是,有一个简单的两步方法。

您可以添加\s 来匹配任何空格,或者添加\pZs\t 来匹配任何水平空格到字符类。我建议先使用\d 捕获号码,然后使用可选的非捕获组,末尾带有数字模式,以确保捕获的号码以数字开头和结尾:

\bTop Rate\b.*?(\d(?:[\d,.\s]*\d)?)

请参阅regex demo。请注意,重复 \s*\s* 没有什么意义,\s* 已经匹配零个或多个空白字符,甚至 \s* 也是多余的,因为 .*? 尽可能少地匹配除 LF 字符之外的任何零个或多个字符。要使其跨行匹配,请添加 RegexOptions.Singleline 选项。

详情

\bTop Rate\b - 一个完整的词Top Rate .*? - 除换行符之外的任何零个或多个字符尽可能少 (\d(?:[\d,.\s]*\d)?) - 第 1 组: \d - 一个数字 (?:[\d,.\s]*\d)? - 一个可选的非捕获组,匹配零个或多个数字、,. 或空格,然后是一个数字。

接下来,当你得到匹配时,只保留数字。

var text = "Top Rate: 8                      88,888";
var result = Regex.Match(text, @"\bTop Rate\b.*?(\d(?:[\d,.\s]*\d)?)", RegexOptions.Singleline);
if (result.Success)

    Console.WriteLine( new string(result.Groups[1].Value.Where(c => char.IsDigit(c)).ToArray()) );

请参阅C# demo。多重匹配:

var text = "Top Rate: 8                      88,888 and Top Rate:                       8  \n   88,888";
var results = Regex.Matches(text, @"\bTop Rate\b.*?(\d(?:[\d,.\s]*\d)?)", RegexOptions.Singleline)
        .Cast<Match>()
        .Select(x => new string(x.Groups[1].Value.Where(c => char.IsDigit(c)).ToArray()));
foreach (var s in results)

    Console.WriteLine( s );

见this C# demo。

【讨论】:

你总是杀死我所有的正则表达式问题!非常感谢你的帮助。这绝对有效。还有一件事。我最近将格式从 int 更改为 decimal。因此,当它到达 IsDigit 部分时,它只会产生 2,500.00 到 250000。我们可以让它像当数字有一个点 (2,500.50) 然后把它作为 2500.50 而当它没有 (888,888) 那么只有 888888.00 吗? @davis 试试this C# demo。我怀疑删除数字和点以外的任何字符都可以。 作品完美,,,永远欣赏它!【参考方案2】:

这样的?

using System;
using System.Text.RegularExpressions;
                    
public class Program

  public static void Main()
  
    string[] texts = 
      "This should Not match the Top Rate thing",
      " Top Rate    : 888,888 ",
      "Top    Rate   : 8 8 8 , 8 8 8 ",
    ;
    Regex rxNonDigit = new Regex(@"\D+"); // matches 1 or more characters other than decimal digits.
    Regex rxTopRate = new Regex(@"
      ^           # match start of line, followed by
      \s*         # zero or more lead-in whitespace characters, followed by
      Top         # the literal 'Top', followed by
      \s+         # 1 or more whitespace characters,followed by
      Rate        # the literal 'Rate', followed by
      \s*         # zero or more whitespace characters, followed by
      :           # a literal colon ':', followed by
      \s*         # zero or more whitespace characters followed by
      (?<rate>    # an named (explicit) capture group, containing
        \d+       # - 1 or more decimal digits, followed by
        (         # - an unnamed group, containing
          (\s|,)+ #     - interstial whitespace or a comma, followed by
          \d+     #     - 1 or more decimal digits
        )*        #   the whole of which is repeated zero or more times
      )           # followed by
      \s*         # zero or more lead-out whitespace characters, followed by
      $           # end of line
    ", RegexOptions.IgnorePatternWhitespace|RegexOptions.ExplicitCapture );

    foreach ( string text in texts )
    
      Match m = rxTopRate.Match(text);
      if (!m.Success)
      
        Console.WriteLine("No Match: '0'", text);
      
      else
      
        string rawValue = m.Groups["rate"].Value;
        string cleanedValue = rxNonDigit.Replace(rawValue, "");
        Decimal value = Decimal.Parse(cleanedValue);

        Console.WriteLine(@"Matched: '0' >>> '1' >>> '2' >>> 3",
          text,
          rawValue,
          cleanedValue,
          value
        );
      
    

  
    

【讨论】:

【参考方案3】:

我验证了,发现只要稍微改动一下Regex语句,就可以达到你的目的。

第一个:

第二个:

【讨论】:

我宁愿不使用 foreach 来完成这项任务,因为我需要多 30 行正则表达式来提取信息,所以这将是一场灾难,并且需要永远逐行提取。而且我已经只使用 if 语句来获取所有值就好了。

以上是关于正则表达式 - 忽略空格的主要内容,如果未能解决你的问题,请参考以下文章

忽略正则表达式中的空格并匹配

正则表达式 - 查找所有空格并忽略多行字符串中的连字符分隔的单词

使用正则表达式的 FluentValidation 不允许 N/A 或 NA 忽略大小写和空格

正则表达式表示空格或者换行

正则表达式只允许单词之间有一个空格

可选的空格正则表达式