正则表达式强制字符串中特定字符的上限

本文关键字:字符 字符串 正则表达式 | 更新日期: 2023-09-27 18:23:49

我有一个单词列表,我需要消除所有出现零次或不超过一次i、零次或不超过两次出现的o和零次或不超过三次出现的单词u

例如:

in会起作用,但inside不会。

onoctopus会起作用,但commotion不会

到目前为止,我最好的猜测似乎并没有完成工作:

Regex regex = new Regex(@"i?|o{0,2}|u{0,3}");
lines = text.Where(x => regex.IsMatch(x)).ToArray(); // text is array containing the words 

正则表达式强制字符串中特定字符的上限

string[] text = new string[] { "in", "inside", "on", "octopus", "commotion" };
Regex regex = new Regex(@"(i.*){2}|(o.*){3}|(u.*){4}");
var lines = text.Where(x => !regex.IsMatch(x)).ToArray(); // text is array containing the words 
foreach (var s in lines)
{
    Console.WriteLine(s);
}

编辑

只有一个警告。由于回溯,此解决方案不会扩展到大量字母。为了改进缩放,必须禁用回溯:

Regex regex = new Regex(@"(?>.*?i){200}|(?>.*?o){300}|(?>.*?u){400}");

您的正则表达式仅检查后续字符,例如 uuu .所以这是行不通的。通常使用正则表达式有点困难,因为您必须运行三个独立的正则表达式来检查每个字符,或者您必须指定这些字符之间的每个可能的顺序组合。

相反,请考虑在没有正则表达式的情况下解决此问题。以下解决方案非常简单,通过最多遍历一次来检查每个字符串:

List<string> words = new List<string> { "in", "inside", "on", "octopus", "commotion" };
var result = words.Where(x =>
{
    var maxCounts = new Dictionary<char, int>{ { 'i', 1 }, { 'o', 2 }, { 'u', 3 } };
    foreach (char c in x)
    {
        if (maxCounts.ContainsKey(c))
        {
            maxCounts[c]--;
            if (maxCounts[c] < 0)
                return false;
        }
    }
    return true;
}).ToArray();

可以使用具有 3 个|交替的简单正则表达式。

用于匹配输入是单个单词。

i.*?i|o(?:.*?o){2}|u(?:.*?u){3}

或者用于匹配文本中的单词。

'b(?:(?>'w*?i){2}|(?>'w*?o){3}|(?>'w*?u){4})'w*
  • 'b匹配单词边界
  • (?:打开非捕获组
  • (?>打开原子组
  • 'w匹配单词字符

在正则表达式中查看演示