简体   繁体   中英

Regex to match all combinations of a given string

I am trying to make a regex to matches all the combinations of a given string. For example of the string is "1234", answers would include:

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

Nonexamples would include:

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

If it matters, the programming language I am using is javascript.

Thank you for any help.

You may use this lookahead based assertions in your regex:

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

RegEx Demo

Here we have 4 lookahead assertions:

  • (?!(?:[^1]*1){2}) : Assert that we don't have more than one instance of 1
  • (?!(?:[^2]*2){2}) : Assert that we don't have more than one instance of 2
  • (?!(?:[^3]*3){2}) : Assert that we don't have more than one instance of 3
  • (?!(?:[^4]*4){2}) : Assert that we don't have more than one instance of 4

We use [1234]+ to match any string with these 4 characters.

A combination of group captures using character classes and negative look-ahead assertions using back-references would do the trick.

Let's begin with simply matching any combination of 1, 2, 3, and 4 using a character class, [1-4] , and allowing any length from 1 to 4 characters. {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))); 

When that code is run, it's easy to see that although only numbers consisting of some combination of 1, 2, 3, and 4 are matched, it also is matching numbers with repeating combinations (eg 11, 22, 33, 112, etc). Obviously, this was not what was desired.

To prevent repeating characters requires a reference to previously matched characters and then a negation of them from any following matched characters. Negative look-aheads, (?!...) using a back-reference, \\1-9 , can accomplish this.

Building on the previous example with a subset of the inputs (limiting to a max length of two characters for the moment) would now incorporate a group match surrounding the first character, ([1-4]) , followed by a negative look-ahead with a back-reference to the first capture, (?!\\1) , and finally a second optional character class.

 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))); 

This matches the desired characters with no repetition!

Expanding this pattern to include back-references for each of the previously matched characters up to the desired max length of 4 yields the following expression.

 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))); 

Hope this helps!

You don't need to use regex for this. The snippet below does the following:

  1. Loop over possible combinations ( a => s ) ( 1 , 123 , 4321 , etc.)
  2. Copy the current combination so as not to overwrite it ( s2 = s )
  3. Loop over the characters of test string ( x => ch ) ( 1234 => 1 , 2 , 3 , 4 )
  4. Replace common characters in the combination string shared with the test string ( s2.replace )
    • For example in the combination 1 , the 1 will be replaced when the loop gets to the character 1 in 1234 resulting in an empty string
  5. If the combination string's length reaches 0 ( s2.length == 0 ) write the result to the console and break out of the loop (no point in continuing to attempt to replace on an empty string)

 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; } } }) 

Results:

1
123
4321
4312

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM