1

Is it possible to find a character based on the previous line match position in regex?

The matching character does not have a fixed position.

Example. Where the # sign is positioned in the first line would match the character value from the next line.

This would give: 2

X#ZEAKBLA
123456789

This would give: 7

XIZEAK#LA
123456789
heldt
  • 4,166
  • 7
  • 39
  • 67
  • 2
    Do you really need to do this using regexp? I imagine the regexp could give you the index, and using this index you can directly access the desired character (`string.charAt(index)` etc.) – C-Otto May 31 '17 at 10:11
  • It depends on regex flavor. I guess it could be done with recursion which is available in some flavors. – SamWhan May 31 '17 at 10:13
  • (Standard) regexes cannot count. It would probably be pretty inefficient with non-standard regexes anyways. – Mateen Ulhaq May 31 '17 at 10:13
  • You could achieve this with IndexOf to find the character, and then just trim the other string to get the value. [documentation](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf) – Foo Bar May 31 '17 at 10:14
  • It could (also) be done with conditions if there's a finite number of characters. – SamWhan May 31 '17 at 10:19
  • 1
    I'm aware that I could solve this with code very easily but now I'm, for fun, trying to solve it with only regex. – heldt May 31 '17 at 10:19

2 Answers2

5

Here's a really complex version using conditionals:

^(?(?=#).*\n(.)|(?(?=.#).*\n.(.)|(?(?=..#).*\n..(.)|(?(?=...#).*\n...(.)|(?(?=^....#).*\n....(.)|(?(?=^.{5}#).*\n.{5}(.)|(?(?=^.{6}#).*\n.{6}(.)|#))))))).*$

Basically what it does is to first check for beginning of line and start a multi leveled conditional (if/then/else).

Then follows a test for an increasing number of any characters, starting with 0 (and in this example going up to 7) and after that it test for a match of #.

If that is fulfilled, it matches the rest of the line, a line feed, and the same number of any character found in the previous test which puts us in the same position as the # from the in above.

So now we just capture a single character, which is the result!

If the match with n characters followed by a # wasn't met, it test the next else which has n+1 charaters before the #, and so on...

If the final test fails, a match for # is made (which in a full scale version shouldn't be present) to make the match fail.

Finally, after closing the conditional, the rest of the line is matched to avoid continued matching on the current line, if a global flag is used.

See it here at regex101.

Edit

Reduced complexity somewhat by movinf the actual capturing out of the test, to outside it at the end, before matched rest of line:

^(?(?=#).*\n|(?(?=.#).*\n.|(?(?=..#).*\n..|(?(?=...#).*\n...|(?(?=....#).*\n....|(?(?=.{5}#).*\n.{5}|(?(?=.{6}#).*\n.{6}|#)))))))(.).*$

Here at regex101.

Edit2

Kinda got stuck on this one ;)

Here's an even simpler version. (I've replaced the index character with (ASCII 254), mainly to allow for comments within the regex, but also to improve readability (imo).)

^               # Match start of line
(?(?=■).*\n|.   # Test if first character is a ■. If not match one of anything
(?(?=■).*\n|.   # Test if second character is a ■. If not match one of anything
(?(?=■).*\n|.   # Test if third character is a ■. If not match one of anything
(?(?=■).*\n|.   # and so on...
(?(?=■).*\n|.   # and so on...
(?(?=■).*\n|.   # and so on...
(?(?=■).*\n|■   # Match a last ! or force a fail (match ■)
.).).).).).).)  # "On the way out" of the match, "eat" characters on the next line
(.).*$          # Capture the character and match the rest of the line

As stated in the comments, it matches an arbitrary character after the match in all levels removing the need for specific match of each levels characters.

This one also makes it very much easier to add levels to the tests.

At regex101.

SamWhan
  • 8,296
  • 1
  • 18
  • 45
0

Regex and slice? As EASY solution to implement, for complexity check best answer in this same question, from @ClasG -amazing

<button onclick="myFunction()">Try it</button>
<p>     "123#4678911" </p>
<p>    1943215927 </p>
<p id="demo"></p>
<p id="demo2"></p>

<script>
function myFunction() {
    var str = "123#4678911"; 
    var otherstr = "1943215927";
    var n = str.search(/#/);
    //returns 3, starts in 0
    var res = otherstr.slice(n,n+1);
    //cut all otherstr between 3 and 4 position
    document.getElementById("demo").innerHTML = "position begnng in [0]:"+n;
    document.getElementById("demo2").innerHTML = "number in 2d string: "+res;

}
</script>
Foo Bar
  • 165
  • 2
  • 14