Regex (.NET), 69 bytes
Try it online! - all test cases
Try it on regex101! - try it on your own
This is a single regex substitution, to be applied once. This is the only kind of substitution that can be efficiently used on regex101.
Input is taken in the form of the two strings delimited by a newline.
The primary challenge here is that each match+substitution must be done as a separate event, with no communication between them (other than that each subsequent match is done following the end of the previous one). No captures can survive from one match to the next, so each one must reconstruct its state from scratch, relying only on the position of the match to let it do that.
Also note that the actual replacement is only done after all matches are found, so that can't be used to communicate state.
In this explanation, a raw newline is shown as
s/ # Match the following:
. # Match a character in string A
(?= # Lookahead (keep this out of what will
# be replaced)
(.*$) # \1 = capture the rest of string A, to
# our position
(?<= # Lookbehind - evaluated from right to
# left, so read from the bottom up
(?= # Lookahead - go back to evaluating from
# left to right.
(?> # Atomic group - after each iteration,
# lock in its match and prevent
.*? # Skip as few characters as possible,
# minimum zero, to match the following:
(.) # \2 = a character in string A
(?= # Lookahead
.*¶ # Skip to the beginning of string T
( # \3 = concatenation of the following:
(?>\3?) # Previous value of \3, if set
(\2) # $4 = the next character in string T
# (which is capitalized)
)+ # Loop the above as many times as
# possible, minimum one, to make the
# following match:
\1$ # Stop at the point we snapshotted,
# making sure that the string ends after
# it, to prevent matching an earlier
^.* # First step in the lookbehind - skip
# back to the beginning of the string.
| # or...
¶.* # Match the newline and string T, in
# order to erase it.
/ # Substitution - replace with this:
$4 # The capital letter we captured in $4,
# which will be empty if it was the
# second alternative that matched.
/ # Flags:
i # Case Insensitive (so that letters in
# string T will match those captured in
# string A)
m # Multiline - "$" matches the end of any
# line instead of just the end of string.
g # Global - replace all matches instead of
# only the first.
regex), 74 bytes
Try it online!
Since mrab-regex supports variable-length lookbehind, the only adaptation necessary in this port was to eliminate the use of nested backreferences. Groups
\5 are copied between each other.
The old version of mrab-regex on TIO has a bug (seemingly similar to an old bug in PCRE1) which necessitated changing
)+?\1$ making the regex 75 bytes, but this is fixed in the latest version (which is not on TIO and not yet on ATO).
Regex (Perl / PCRE), 86 bytes
Try it online! - Perl - all test cases
Try it online! - PCRE1 - all test cases
Try it online! - PCRE2 v10.33 / Attempt This Online! - PCRE2 v10.40+ - all test cases
Try it on regex101! - PCRE1/PCRE2 - try it on your own
This is a port of the .NET regex, emulating variable-length lookbehind using recursion with fixed-length lookbehind, but there's an additional challenge. The .NET regex makes a capture inside the lookbehind which is used as the substitution replacement. That is impossible in Perl/PCRE, since all captures made inside a subroutine (recursive or not) are erased upon exiting it.
So to communicate back from the emulated lookbehind, this regex makes a guess (
\3, captured by
(.)+) as to what the capital letter in string
t will be, and then compares that with the capital letter actually matched inside the lookbehind (
(?=\3)\5). If it's not a match, the regex will backtrack to before the emulated lookbehind, and try capturing a different capital letter from string