【问题标题】:.NET Regex for whitelisted characters.NET 正则表达式用于白名单字符
【发布时间】:2009-08-20 16:17:09
【问题描述】:

考虑需要确定string 是否包含白名单字符之外的任何字符的算法。

白名单如下所示:

'-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÖÜáíóúñÑÀÁÂÃÈÊËÌÍÎÏÐÒÓÔÕØÙÚÛÝßãðõøýþÿ

注意:此白名单中需要包含空格和撇号。

通常这将是一个静态方法,但它会被转换为扩展方法。

private bool ContainsAllWhitelistedCharacters(string input)
{
  string regExPattern="";// the whitelist
  return Regex.IsMatch(input, regExPattern);
}

注意事项:

感谢所有回答者的表现。性能不是问题。质量、可读性和可维护性是!更少的代码 = 更少的缺陷机会,IMO。

问题:

这个白名单正则表达式模式应该是什么?

【问题讨论】:

  • 如果你像这样为string 做一个扩展方法,它表明所有字符串都受制于它们可以包含和不能包含的白名单,但事实并非如此。
  • @28:感谢您的评论。我意识到所有string 成员都可以使用该方法。开发人员应该明智地调用扩展方法,就像将其实现为实用方法一样。
  • @pcampbell:您应该创建一个不可变结构,其中包含一个已知不包含任何坏字符的字符串(在构造函数中检查)。这样,与Path 类不同,您可以对字符串进行操作,而无需执行 O(n) 检查错误字符。

标签: c# .net regex


【解决方案1】:

为什么必须是正则表达式?

private bool ContainsAllWhitelistedCharacters(string input)
{
  string whitelist = "abcdefg...";
  foreach (char c in input) {
    if (whitelist.IndexOf(c) == -1)
      return false;
  }
  return true;
}

如果您不确定如何实现所需的正则表达式,并且您还没有分析该部分代码并发现您需要额外的性能,则无需直接跳入正则表达式。

【讨论】:

  • 嗯...这不起作用那么为什么所有的赞成票?如果字符串中有无效字符,它不会捕获。
  • 谢谢马克。不幸的是,此建议 IndexOfAny 不会返回过滤掉未列入白名单的字符,例如“_”或“5”。
  • 是的,我刚刚意识到这一点并把它拿出来——这真的不应该得到任何支持。任何支持它的人都没有读过它:X
【解决方案2】:

您可以使用以下方式进行模式匹配:

^([\-\.a-zA-Z ÇüéâäàåçêëèïîíìÄÅÉæÆôöòûùÖÜáíóúñÑÀÁÂÃÈÊËÌÍÎÏÐÒÓÔÕØÙÚÛÝßãðõøýþÿ]+)$

使其成为扩展方法:

public static bool IsValidCustom(this string value)
{
    string regExPattern="^([\-\.a-zA-Z ÇüéâäàåçêëèïîíìÄÅÉæÆôöòûùÖÜáíóúñÑÀÁÂÃÈÊËÌÍÎÏÐÒÓÔÕØÙÚÛÝßãðõøýþÿ]+)$";
    return Regex.IsMatch(input, regExPattern);
}

我想不出一种简单的方法来使用扩展字符来实现可维护范围,因为字符的顺序并不明显。

【讨论】:

  • 我认为上述模式需要稍微调整以允许空白值。此外,请考虑使用内置字符类“\w”,而不是尝试枚举所有受支持语言的字母表。这将引入下划线和数字,然后需要第二个 RegEx 来排除,但会在尝试重新发明字符类的过程中节省大量潜在的维护。
  • 我已经测试过了,它适用于空间。这是一个硬编码的值列表,空格包含在 Z 之后。唯一的范围是 a-z 和 A-Z 中的字符
【解决方案3】:

我不知道正则表达式后端是如何实现的,但使用以下内容匹配列表之外的任何内容可能是最有效的:

private bool ContainsAllWhitelistedCharacters(string input)
{
   Regex r = new Regex("[^ your list of chars ]");
   return !r.IsMatch(test)
}

【讨论】:

  • 双重否定并不令人困惑。
  • 我同意,我建议这样做假设它是 c# 中更有效的正则表达式。有谁知道这是真的还是假的?我对答案很感兴趣。
  • 花了很多时间试图解决同样的问题。最后,采用这种双重否定的方法,一切都好起来了。
【解决方案4】:

请注意,除非性能确实有问题,否则我不建议这样做,但我想我会指出,即使包括预编译正则表达式,您也可以做得更快:

比较:

static readonly Regex r = new Regex(
  @"^(['\-\.a-zA-Z ÇüéâäàåçêëèïîíìÄÅÉæÆôöòûùÖÜáíóúñÑ"+
   "ÀÁÂÃÈÊËÌÍÎÏÐÒÓÔÕØÙÚÛÝßãðõøýþÿ]+)$");

public bool IsValidCustom(string value)
{
  return r.IsMatch(value);
}

与:

private bool ContainsAllWhitelistedCharacters(string input)
{
    foreach (var c in input)
    {
        switch (c)
        {
            case '\u0020': continue; 
            case '\u0027': continue; 
            case '\u002D': continue; 
            case '\u002E': continue; 
            case '\u0041': continue; 
            case '\u0042': continue; 
            case '\u0043': continue; 
            case '\u0044': continue; 
            case '\u0045': continue; 
            case '\u0046': continue; 
            case '\u0047': continue; 
            case '\u0048': continue; 
            case '\u0049': continue; 
            case '\u004A': continue; 
            case '\u004B': continue; 
            case '\u004C': continue; 
            case '\u004D': continue; 
            case '\u004E': continue; 
            case '\u004F': continue; 
            case '\u0050': continue; 
            case '\u0051': continue; 
            case '\u0052': continue; 
            case '\u0053': continue; 
            case '\u0054': continue; 
            case '\u0055': continue; 
            case '\u0056': continue; 
            case '\u0057': continue; 
            case '\u0058': continue; 
            case '\u0059': continue; 
            case '\u005A': continue; 
            case '\u0061': continue; 
            case '\u0062': continue; 
            case '\u0063': continue; 
            case '\u0064': continue; 
            case '\u0065': continue; 
            case '\u0066': continue; 
            case '\u0067': continue; 
            case '\u0068': continue; 
            case '\u0069': continue; 
            case '\u006A': continue; 
            case '\u006B': continue; 
            case '\u006C': continue; 
            case '\u006D': continue; 
            case '\u006E': continue; 
            case '\u006F': continue; 
            case '\u0070': continue; 
            case '\u0071': continue; 
            case '\u0072': continue; 
            case '\u0073': continue; 
            case '\u0074': continue; 
            case '\u0075': continue; 
            case '\u0076': continue; 
            case '\u0077': continue; 
            case '\u0078': continue; 
            case '\u0079': continue; 
            case '\u007A': continue; 
            case '\u00C0': continue; 
            case '\u00C1': continue; 
            case '\u00C2': continue; 
            case '\u00C3': continue; 
            case '\u00C4': continue; 
            case '\u00C5': continue; 
            case '\u00C6': continue; 
            case '\u00C7': continue; 
            case '\u00C8': continue; 
            case '\u00C9': continue; 
            case '\u00CA': continue; 
            case '\u00CB': continue; 
            case '\u00CC': continue; 
            case '\u00CD': continue; 
            case '\u00CE': continue; 
            case '\u00CF': continue; 
            case '\u00D0': continue; 
            case '\u00D1': continue; 
            case '\u00D2': continue; 
            case '\u00D3': continue; 
            case '\u00D4': continue; 
            case '\u00D5': continue; 
            case '\u00D6': continue; 
            case '\u00D8': continue; 
            case '\u00D9': continue; 
            case '\u00DA': continue; 
            case '\u00DB': continue; 
            case '\u00DC': continue; 
            case '\u00DD': continue; 
            case '\u00DF': continue; 
            case '\u00E0': continue; 
            case '\u00E1': continue; 
            case '\u00E2': continue; 
            case '\u00E3': continue; 
            case '\u00E4': continue; 
            case '\u00E5': continue; 
            case '\u00E6': continue; 
            case '\u00E7': continue; 
            case '\u00E8': continue; 
            case '\u00E9': continue; 
            case '\u00EA': continue; 
            case '\u00EB': continue; 
            case '\u00EC': continue; 
            case '\u00ED': continue; 
            case '\u00EE': continue; 
            case '\u00EF': continue; 
            case '\u00F0': continue; 
            case '\u00F1': continue; 
            case '\u00F2': continue; 
            case '\u00F3': continue; 
            case '\u00F4': continue; 
            case '\u00F5': continue; 
            case '\u00F6': continue; 
            case '\u00F8': continue; 
            case '\u00F9': continue; 
            case '\u00FA': continue; 
            case '\u00FB': continue; 
            case '\u00FC': continue; 
            case '\u00FD': continue; 
            case '\u00FE': continue; 
            case '\u00FF': continue;        
        }
        return false;     
    }    return true; // empty string is true    
}

在对通过率约为 60% 的词库进行非常快速的测试时,我使用这种方法的速度提高了大约 8 倍。

实际上它的可读性并不比没有转义字符的正则表达式差多少!

【讨论】:

    猜你喜欢
    • 2012-06-12
    • 1970-01-01
    • 2021-05-06
    • 1970-01-01
    • 2018-12-23
    • 2022-01-25
    • 2023-03-27
    • 2011-03-01
    • 1970-01-01
    相关资源
    最近更新 更多