use v5.12; use warnings; use Test::More; my $escaped = qr/\\./; my $quoted = qr/ (['"]) # --- start-quote (?: # --- inside $escaped # any escape-pair | . # anything else )*? # non-greedy (?: # --- end \g{-1} # same quote | $ # EOL ends missing pair ) /x; my $re = qr/ (?: $escaped # any escape pair | $quoted # any quoted string | \S # any none whitespace )+ # at least once /x; my $str = q{This "is so" very simple.}; my @tests = ( # q{all '- and "-quotes properly balanced}, [ q{This is simple.}, [ q{This}, q{is}, q{simple.} ] ], [ q{ This is simple. }, [ q{This}, q{is}, q{simple.} ] ], [ q{This is "so very simple".}, [ q{This}, q{is}, q{"so very simple".} ] ], [ q{This "is so" very simple.}, [ q{This}, q{"is so"}, q{very}, q{simple.} ] ], [ q{This 'isn\'t nice.'}, [ q{This}, q{'isn\'t nice.'} ] ], [ q{This "isn\"t nice."}, [ q{This}, q{"isn\"t nice."} ] ], [ q{This 'isn\\\\'t nice.'}, [ q{This}, q{'isn\\\\'t}, q{nice.'} ] ], [ q{This "isn\\\\"t nice."}, [ q{This}, q{"isn\\\\"t}, q{nice."} ] ], [ q{This 'is not unnice.'}, [ q{This}, q{'is not unnice.'} ] ], [ q{This "is not unnice."}, [ q{This}, q{"is not unnice."} ] ], [ q{a "bb cc" d}, [ q{a}, q{"bb cc"}, q{d} ] ], # q{UNbalanced '- and "-quotes at absolute end of string}, [ q{This is "so very simple}, [ q{This}, q{is}, q{"so very simple} ] ], [ q{This 'isn\'t nice.}, [ q{This}, q{'isn\'t nice.} ] ], [ q{This "isn\"t nice.}, [ q{This}, q{"isn\"t nice.} ] ], [ q{This 'isn\\\\'t nice.}, [ q{This}, q{'isn\\\\'t}, q{nice.} ] ], [ q{This "isn\\\\"t nice.}, [ q{This}, q{"isn\\\\"t}, q{nice.} ] ], [ q{This 'is not unnice.}, [ q{This}, q{'is not unnice.} ] ], [ q{This "is not unnice.}, [ q{This}, q{"is not unnice.} ] ], # 'what about these questionable cases?', [ q{is this"really so"simple now?}, [ q{is}, q{this"really so"simple}, q{now?} ] ], [ q{is this"really so" now?}, [ q{is}, q{this"really so"}, q{now?} ] ], [ q{is "really so"simple now?}, [ q{is}, q{"really so"simple}, q{now?} ] ], [ q{is this'really so'simple now?}, [ q{is}, q{this'really so'simple}, q{now?} ] ], [ q{is this'really so' now?}, [ q{is}, q{this'really so'}, q{now?} ] ], [ q{is 'really so'simple now?}, [ q{is}, q{'really so'simple}, q{now?} ] ], ); plan tests => 0+@tests; for my $test (@tests) { my ($str, $exp) = @$test; my $got; push @$got, $& while ($str =~ /$re/g); is_deeply($got, $exp, qq{<$str>: } . join('|', @$exp)); }