正则表达式匹配给定字符串的所有组合

Regex to match all combinations of a given string

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

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

非示例包括:

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

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

感谢您的帮助。

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

^(?!(?:[^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个字符的任何字符串。

您不需要为此使用正则表达式。下面的代码片段执行以下操作:

  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

使用字符 classes 的组捕获和使用反向引用的否定前瞻断言的组合可以达到目的。

让我们首先使用字符 class、[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 等)。显然,这不是我们想要的。

要防止重复字符,需要引用先前匹配的字符,然后从任何后续匹配的字符中取反。否定前瞻,(?!...) 使用反向引用,-9,可以实现这一点。

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

const regex = /^([1-4])(?!)[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-4])?((?!|)[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)));

希望对您有所帮助!