Regexp match should be different for \z and \Z, but isn't

irb(main):024:0> “abc\n\de\nfghi\n” =~ /\A(.?)\n(.)\z/m and puts
“’#{$2}’”
‘de
fghi

=> nil
irb(main):025:0> “abc\n\de\nfghi\n” =~ /\A(.?)\n(.)\Z/m and puts
"’#{$2}’"
'de
fghi

=> nil

The difference between those cases is only \z vs. \Z.

I had expected, that in the first case (.*) matches also the final \n,
while in the first case the final newline should be omitted, but I get
the same result in both cases. Why?

Because preceding greedy pattern (.*) swallows the last newline
character in multi-line mode and \Z still can succeed, because \n at the
end of string is optional and as not available in this case, it won’t
get excluded.

If you make the last group pattern non-greedy, it would behave as you
are expecting:

“abc\n\de\nfghi\n” =~ /\A(.?)\n(.?)\z/m and puts
“’#{$2}’”
'de
fghi

“abc\n\de\nfghi\n” =~ /\A(.?)\n(.?)\Z/m and puts
“’#{$2}’”
‘de
fghi’

Thanks for the clear explanation!