需要帮助扩展anagram regex

时间:2013-03-01 11:18:08

标签: regex anagram

我正在尝试扩展此正则表达式,以列出给定字母集的所有可能的字谜:

^(?!.*([aer]).*\1)(?!(.*d){4})([aerd]*|[a-z])$

到目前为止,基于这个正则表达式,我可以收到由字母'dadder'组成的任何单词和子单词组合的匹配,例如'adder','add','ad','red'正则表达式复杂性的原因而不是简单的[dadder]*是因为显然每个字母可以匹配无限次,这很糟糕,我希望每个字母只匹配测试字符串一次,如果有两个提供,它可以匹配最多两次或更少。如果某人当然可以简化正则表达式以匹配指定X次的任何字母组合,请随时提供:)

然而,我的主要问题是,我现在想要加入一个句号“。”。如果在字符列表中遇到句号,则它充当通配符并且可以匹配任何字符a-z。因此dadd.r可以匹配daddzrdaddordaddprrpdadd等。

有人可以帮我吗?

3 个答案:

答案 0 :(得分:1)

这不是一个应该用正则表达式解决的问题,因为nhahtdh's amusing answer应该说服你。

正则表达式擅长匹配模式。它们不是解决基于集合的问题的工具,而是您尝试使用它们的工具。

你真的需要一种算法方法,因为这就是问题的本质。 This question涵盖了这样一个话题。

答案 1 :(得分:1)

问题的第一部分是这个问题的重复:Check if string is subset of a bunch of characters? (RegEx)?


这个答案致力于解决您面临的实际问题(问题的第二部分)。

一个非常简单的解决方案是使用2个地图:一个用于映射原始集中字符的频率,并记录.的数量,另一个用于映射每个字符的频率输入字符串。

伪代码:

// I assume the maps return 0 for non existent entries
// Depending on the input, the map can simply be an array, or a tree/hash map

function checkAnagramExtended(originalString, inputString):
    if (inputString.length > originalString.length):
        return false

    // The frequency mapping for original string (ref stands for reference)
    // Ideally, refMap should be filled up once instead of every call
    // to this function
    var refMap = countFrequency(originalString)
    // The frequency mapping for input string
    var inpMap = empty map

    foreach (character c in inputString):

        if (inpMap[c] >= refMap[c]):
            // You may want to check that c is a character allowed
            // to be substituted by dot .
            // if (!canBeSubstitutedByDot(c)):
            //     return false

            if (inpMap['.'] >= refMap['.']):
                return false
            else:
                inpMap['.'] += 1

        else:
            inpMap[c] += 1

    return true

附录:扩展正则表达式解决方案?

您的点.扩展名允许a-z中的任何字符匹配,这使得正则表达式解决方案变得更加不切实际。

在我对另一个问题的解决方案中,我严重依赖负面预测来断言一个特定字符的数量小于多字符字符中的最大字符数。 / p>

.扩展名可以改变任何字符允许的最大字符数,从而打破了上面的解决方案。如果你强制正则表达式完成这项工作,如果只有1 .,则可以生成正则表达式,但是当你将它增加到2时会爆炸。

答案 2 :(得分:0)

好的,经过多次努力试图将其作为正则表达式,我放弃了,因为不完整的通配符支持和缓慢的处理时间。

我现在已经将我的要求转换为C#功能了,我现在实际上更加舒适和快乐,因为它的速度也提高了约400%,非常棒。

这将检查给定单词是否是通过(。)支持通配符的一组字母的字谜或子字谜。

其中letters是要对字谜进行测试的字母。

其中dictionaryData是要测试的List<string>个字词。

var letterCounts = letters.Select(x => x)
  .GroupBy(x => x)
  .ToDictionary(x => x.Key, x => x.Count());

var containsWildcards = letters.IndexOf('.') >= 0;
foreach (var dictWord in dictionaryData)
{
    var matches = 0;
    var dictWordLength = dictWord.Length;
    if (dictWordLength > letters.Length)
        continue;
    var addedChars = new List<char>();
    foreach (var dictLetter in dictWord)
    {
        var foundLetter = false;
        if (letterCounts.ContainsKey(dictLetter) &&
            addedChars.Count(x => x == dictLetter) < letterCounts[dictLetter])
        {
            if (letters.IndexOf(dictLetter) >= 0)
                foundLetter = true;
        }
        else if (containsWildcards &&
            addedChars.Count(x => x == '.') < letterCounts['.'])
        {
            addedChars.Add('.');
            foundLetter = true;
        }
        if (foundLetter)
        {
            addedChars.Add(dictLetter);
            matches++;
        }
        if (dictWordLength == matches)
            break;
    }

    if (dictWordLength <= matches)
    {
        // We have a match!
    }
}

希望它也可以帮助别人。