【问题标题】:Regex - match words which only consists of certain characters and certain char is repeated certain times正则表达式 - 匹配仅包含某些字符且某些字符重复某些次的单词
【发布时间】:2017-07-06 18:55:09
【问题描述】:

我有包含 300 000 多个单词的单词数据库

我想匹配长度已知的单词(例如 7)并且它包含 只有某些字符,其中一些字符可以重复某些次,但不是全部

例如

我有 a,p,p,l,e,r,t,h,o 字符,我想找到长度为 5 的单词

所以,它可以匹配

apple
earth

但不是

hello 因为l 被指定了不止一次

我的尝试

 ^([a,p,p,l,e,r,t,h,o]{1}) # capture first char 

 (!/1 [a,p,p,l,e,r,t,h,o]{1}) # capture second char but without firstly captured symbol

 (!/1 !/2 [a,p,p,l,e,r,t,h,o]{1}) # capture third char but without first and second captured symbol

and so on  ...

【问题讨论】:

  • PLS,评论一下这个问题有什么问题,我会纠正它,而不是投反对票
  • 你的任意应该匹配/不应该匹配的例子并不清楚底层逻辑应该是什么。描述那个。另外,SO 不是“我想要,你做”类型的网站。你需要向我们展示你的尝试。
  • 不确定是否应该首先使用正则表达式...但是如果必须这样做,我可能会首先按字母顺序对所有这些单词的字符进行排序(通过您的附加列表),因为创建一个涵盖这些字母的所有可能顺序的正则表达式不会很有趣。然后你使用匹配的量词创建你的正则表达式 - 所以对于你最初包含字母 a 的示例,这可能是一个简单的a?,对于出现两次的 p,p{0,2} - 匹配零到两个 p 字符等.
  • 使用正则表达式可以解决很多问题,但这真的不是正则表达式问题。您应该尝试创建一种方法来计算单词中的字符,并根据预期的字符数进行检查。我必须承认这是一个有趣的问题
  • @CBroe 这是一个有趣的解决方案 :)

标签: regex


【解决方案1】:

试试下面的正则表达式:

\b(?!\w*([alertho])\w*\1)(?!\w*([p])(\w*\2){2})[aplertho]{5}\b

详情:

  • \b - 字边界(开头)。
  • (?!\w*([alertho])\w*\1) - 负前瞻,测试超过 1 出现提到的字符):
    • 一些单词字符(可选),
    • 允许出现一次的字符之一(捕获 groupp #1),
    • 一些单词字符(可选),
    • 与 groupp #1 捕获的字符相同。
  • (?!\w*([p])(\w*\2){2}) - 负前瞻,测试是否发生更多 超过 2 倍。 和以前一样,但这次:
    • 捕获组有2号,
    • 允许的字符集仅包含 p,
    • 如果发生 groupp #2 捕获的字符,则此先行“触发” 此后两次
  • [aplertho]{5} - 我们正在寻找的 - 任何允许的字符, 5 次。
  • \b - 字边界(关闭)。

【讨论】:

  • 如果我有 a,p,p,l,e,r,t,h,o,o,g,g 并想匹配 googl 怎么办?
  • 应该是\b(?!\w*([alerth])\w*\1)(?!\w*([p])(\w*\2){2})[aplertgho]{5}\b ?
  • 在三个地方进行更改: 1. 从第一个捕获组中删除 o。 2. 将 go 添加到第二个捕获组。 3.更改要匹配的字符数,例如到{5,6}google 有 6 个字符)。
【解决方案2】:

我知道这不是问题的正则表达式解决方案,但有时正则表达式不是解决方案。

public class WordChecker
{
    public WordChecker(params char[] letters)
    {
        Counters = letters.GroupBy(c => c).ToDictionary(g => g.Key, g => new Counter(g.Count()));
    }
    public WordChecker(string letters) : this(letters.ToArray())
    {
    }

    public bool CheckWord(string word)
    {
        Initialize();
        foreach (var c in word)
        {
            Counter counter;
            if (!Counters.TryGetValue(c, out counter)) return false;
            if (!counter.Add()) return false;
        }
        return true;
    }

    private void Initialize()
    {
        foreach (var counter in Counters)
            counter.Value.Initialize();
    }
    private Dictionary<char, Counter> Counters;
    private class Counter
    {
        public Counter(int maxCount)
        {
            MaxCount = maxCount;
            Count = 0;
        }
        public void Initialize()
        {
            Count = 0;
        }
        public bool Add()
        {
            Count++;
            return Count <= MaxCount;
        }
        public int MaxCount { get; private set; }
        public int Count { get; private set; }
    }
}

而使用方法是这样的:

    WordChecker checker = new WordChecker("applertho");
    List<string> words = new List<string>(){"apple", "giraf", "earth", "hello"};
    foreach (var word in words)
        if (checker.CheckWord(word))
        {
            // The word is valid!
        }

【讨论】:

  • 感谢 Casperah :) 问题是我不想修改已经存在的源代码(它是用 node.js 编写的)。现有的源代码可以使用 regex 在 db 中搜索单词,所以我只想要相应的 regex 语句
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-07-05
  • 1970-01-01
  • 1970-01-01
  • 2011-05-05
  • 2020-08-25
  • 1970-01-01
  • 2017-07-25
相关资源
最近更新 更多