in reply to /g option not making s// find all matches

FYI, One possible way to do what you want is:

while (<DATA>) { next unless /^~/;# Skip line unless it starts with ~ tr/_/+/; } continue { print; }

The reason your /g version doesn't match is because /g doesn't try to match several times from the start of the string, but from the position last match. So after turning "~a_b_c_d" into "~a+b_c_d" it will start looking after the +, in the substring "b_c_d". Because this substring is not at the beginning of the string, ^ fails, (and ~ would obviously fail as well).

The \G anchor, meaning "from the last match" let's you express "and underscore after a ~ or any underscore after that":

pos($_) = -1; s/(^~ | \G) .*? \K _ /+/gx;
(^~|\G) can either match a ~ at the beginning of a string, or at the position of the last match. But since I have forced that position at -1, ^~ is the only possible alternative on the first try. Beyond that point, the s/// will run in a loop, where ^~ fails (because not at the beginning of the string), but \G matches the position of the last iteration.

NB: because $_ is the default variable, pos($_) = -1 can be simplified to pos = -1

NB2: and the reason jwkrahn's solution works is because instead of using /g, it calls the s/// operator in a loop, meaning it starts over again on each iteration (after turning "~a_b_c_d", it will run on "~a+b_c_d").

Replies are listed 'Best First'.
Re^2: /g option not making s// find all matches
by raygun (Scribe) on May 28, 2018 at 09:17 UTC
    /g doesn't try to match several times from the start of the string, but from the position last match.
    Thank you! This is the kernel of wisdom I was overlooking. Thank you both for the various working solutions.
Re^2: /g option not making s// find all matches
by vr (Curate) on May 29, 2018 at 17:53 UTC
    But since I have forced that position at -1

    Which only works because input wasn't chomped, right? I wonder if someone misreads it as "which makes \G match nowhere". While, assigning negative values to pos counts leftward from the end (similar to parameter of substr, or negative array subscript, etc.). Surprise or not, this pos behavior isn't documented (nor silent clumping if value is out of bounds).

      I wonder if someone misreads it as "which makes \G match nowhere"
      Well I miswrote it as that, I didn't know about the negative value of pos. pos = length will behave better in that case.