【问题标题】:Regex to match all combinations of a given string正则表达式匹配给定字符串的所有组合
【发布时间】:2018-04-17 15:50:56
【问题描述】:

我正在尝试制作一个正则表达式来匹配给定字符串的所有组合。例如字符串是“1234”,答案包括:

  1. “1”
  2. “123”
  3. “4321”
  4. “4312”

非示例包括:

  1. “11”
  2. “11234”
  3. “44132”

如果重要的话,我使用的编程语言是 javascript。

感谢您的帮助。

【问题讨论】:

  • Regex 很可能是错误的方式来完成你想要做的任何事情。
  • 有什么好的方法可以做到这一点?
  • 对您的候选人进行排序并与原件进行比较(假设原件已经按照您的示例进行了排序)。
  • 我看到你在做一个简单的[1-4]+
  • @VishnuMurthy 有没有回答您的问题?

标签: javascript regex regex-lookarounds regex-greedy


【解决方案1】:

你可以在你的正则表达式中使用这个基于前瞻的断言:

^(?!(?:[^1]*1){2})(?!(?:[^2]*2){2})(?!(?:[^3]*3){2})(?!(?:[^4]*4){2})[1234]+$

RegEx Demo

这里我们有 4 个前瞻断言:

  • (?!(?:[^1]*1){2}):断言我们没有超过一个 1 实例
  • (?!(?:[^2]*2){2}):断言我们没有超过一个 2 的实例
  • (?!(?:[^3]*3){2}):断言我们没有超过一个 3 实例
  • (?!(?:[^4]*4){2}):断言我们没有超过一个 4 实例

我们使用[1234]+ 来匹配任何包含这4 个字符的字符串。

【讨论】:

    【解决方案2】:

    使用字符类的组捕获和使用反向引用的否定前瞻断言的组合可以解决问题。

    让我们首先使用字符类[1-4] 简单地匹配 1、2、3 和 4 的任意组合,并允许 1 到 4 个字符的任意长度。 {1,4}

    const regex = /^[1-4]{1,4}$/;
    
    // Create set of inputs from 0 to 4322
    const inputs = Array.from(new Array(4323), (v, i) => i.toString());
    
    // Output only values that match criteria
    console.log(inputs.filter((input) => regex.test(input)));

    运行该代码时,很容易看到虽然只有由 1、2、3 和 4 的某种组合组成的数字被匹配,但它也匹配具有重复组合的数字(例如 11、22、33、112 , ETC)。显然,这不是我们想要的。

    为了防止重复字符,需要引用以前匹配的字符,然后从任何后续匹配的字符中取反。使用反向引用 \1-9 的负前瞻 (?!...) 可以完成此操作。

    在上一个示例的基础上,使用输入的子集(目前限制为两个字符的最大长度)现在将包含一个围绕第一个字符 ([1-4]) 的组匹配,然后是一个负前瞻对第一个捕获 (?!\1) 的反向引用,最后是第二个可选字符类。

    const regex = /^([1-4])(?!\1)[1-4]?$/;
    
    // Create set of inputs from 0 to 44
    const inputs = Array.from(new Array(45), (v, i) => i.toString());
    
    // Output only values that match criteria
    console.log(inputs.filter((input) => regex.test(input)));

    这匹配所需的字符,没有重复!

    扩展此模式以包含每个先前匹配的字符的反向引用,最大长度为 4 会产生以下表达式。

    const regex = /^([1-4])((?!\1)[1-4])?((?!\1|\2)[1-4])?((?!\1|\2|\3)[1-4])?$/;
    
    // Create set of inputs from 0 to 4322
    const inputs = Array.from(new Array(4323), (v, i) => i.toString());
    
    // Output only values that match criteria
    console.log(inputs.filter((input) => regex.test(input)));

    希望这会有所帮助!

    【讨论】:

      【解决方案3】:

      您不需要为此使用正则表达式。下面的 sn-p 做了以下事情:

      1. 循环可能的组合 (a => s)(11234321 等)
      2. 复制当前组合以免被覆盖 (s2 = s)
      3. 遍历测试字符串的字符 (x => ch) (1234 => 1, 2, 3, 4)
      4. 替换与测试字符串共享的组合字符串中的常用字符 (s2.replace)
        • 例如在1 组合中,当循环到达1234 中的字符1 时,1 将被替换,从而导致空字符串
      5. 如果组合字符串的长度达到0 (s2.length == 0) 将结果写入控制台并跳出循环(继续尝试替换空字符串没有意义)

      const x = "1234"
      const a = ["1","123","4321","4312","11","11234","44132"]
      
      a.forEach(function(s) {
        var s2 = s
        for(var ch of x) {
          s2 = s2.replace(ch, '')
          if(s2.length == 0) {
            console.log(s);
            break;
          }
        }
      })

      结果:

      1
      123
      4321
      4312
      

      【讨论】:

        猜你喜欢
        • 2013-10-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-09
        • 1970-01-01
        相关资源
        最近更新 更多