正则表达式字符串仅包含允许的字符并限制字符的出现

时间:2018-06-09 12:00:14

标签: c# regex

这是我的角色出现限制。

Dictionary<string,int> chracterLimit=new  Dictionary<string,int>{{"c",1,"a",2}};

这是我输入的字符串......

var mystring="caac";

在这里,我检查LINQ中字符的出现是否有效,以及是否使用超过允许的限制。

bool checkstringvalid=!mystring
  .ToCharArray()
  .Select(c => c.ToString())
  .GroupBy(g => g)
  .ToList()
  .ToDictionary(
     d => d.FirstOrDefault(), 
     d => d.Count())
  .Any(z => z.Value > chracterGroup[z.Key]);

上述条件的输出是> 它是一个无效的字符串。因为c的出现是2但允许的限制只有1。

  

当我使用此功能时,批量数据需要更多时间......   我的问题是如何更容易地检查这个?

你可以通过正则表达式给我一个解决方案吗? 我想象/ / {0,2} / / c {0,1} /

提前致谢!)

4 个答案:

答案 0 :(得分:1)

LINQ引擎非常智能,因此您不太可能从目前的性能中获得很大的性能提升。你可以做的一件事是削减不必要的操作。你所拥有的更清晰的版本是:

int s;
bool violation = myString.GroupBy(c => c.ToString())
                         .Any(g => characterLimit.TryGetValue(g.Key, out s) && s < g.Count());

这消除了从字符串,字符数组,列表到字典的转换。

对于比这更快的事情,你需要抛弃LINQ并采用迭代方法。

答案 1 :(得分:1)

当使用符号工作时,让我们使用字符,而不是字符串(我们不想要过分ToString(),不是吗?):< / p>

   Dictionary<char, int> chracterLimit = new  Dictionary<char,int>{
     {'c', 1},
     {'a', 2}
   };

然后让我们检测计数器示例早期,即如果我们有"aaaaaaaaa....aaa",我们必须首先阅读 <{em> 3 a,不是整个字符串:

   Dictionary<char, int> actual = new Dictionary<char, int>();

   bool checkStringValid = true;

   foreach (char c in mystring) {
     int count = 0;

     if (actual.TryGetValue(c, out count))
       actual[c] = ++count;  
     else
       actual.Add(c, ++count);

     if (chracterLimit.TryGetValue(c, out var limit)) {
       if (count > limit) {
         checkStringValid = false; // limit exceeded

         break;   
       } 
     }
     else {
       checkStringValid = false;  // invalid charcater detected

       break;   
     } 
   }  

以上代码是 speed 的优化;如果您只想寻找更多可读解决方案:

  bool checkstringvalid = !mystring
    .GroupBy(c => c)
    .Any(chunk => chracterLimit.TryGetValue(chunk.Key, out var limit)
       ? chunk.Skip(limit).Any()
       : true);

答案 2 :(得分:1)

您的LINQ表达式中有很多转换。

相反,这种事情怎么样?

 bool IsStringCompliant (string str, Dictionary<char><int> limits) 
 {
     var lim = new Dictionary<char><int>(limits);  // copy dict, allows re-use
     foreach (var c in str) {
       if (lim.ContainsKey(c)) {
           lim[c] -= 1;
           if (lim[c] <= 0) return false;
       }
       else return <<whatever result you want when a char is not in dict>>
    }
    return true;
 }

然后执行此操作以使用该功能。

   var characterLimit = new  Dictionary<string,int>{{'c',1,'a',2}};
   var mystring="caac";
   bool checkstringvalid = IsStringCompliant(mystring, characterLimit);

由于一些原因,这将很快。

  1. 尽可能使用长度为1的char而不是string个变量。
  2. 它起到了C#编译器的循环优化技术的作用。
  3. 一旦知道字符串的有效性失败就会停止搜索。
  4. 另外,下一个程序员更容易理解。

答案 3 :(得分:1)

我不知道你为什么要在这里使用正则表达式解决方案。最后,我不会更快。可以说,如果你超越你的简单例子,那就更复杂了。

仅出于演示目的,这是您将原始条件转换为正则表达式:

  • 允许最多一个c
  • 允许最多两个a
^(?![^c\n]*c[^c\n]*c)(?![^a\n]*a[^a\n]*a[^a\n]*a).*$

Demo

这里的想法是断言一个违反上述规则的模式:两个c或三个a使用否定字符类的负前瞻作为修改后的.。还有其他方法可以做到这一点。您应该已经确信不要使用正则表达式执行此任务。