If we check your code and print the matches:
while ($token =~ /^([^\n]*?)(\n)(.*)$/mg) {
print Dumper $1,$2,$3;
}
We can see:
$VAR1 = 'ACCOUNT_CHANGED = "20250728081545Z"';
$VAR2 = '
';
$VAR3 = 'ACCOUNT_CHANGED_T = "1753690545"';
$VAR1 = 'COMMON_NAME = "User Test"';
$VAR2 = '
';
$VAR3 = 'CURRENT_TIME_T = "1753863424"';
$VAR1 = 'INSTANCE = "testing"';
$VAR2 = '
';
$VAR3 = 'TEMPLATE_TIME_T = "1753699621"';
$VAR1 = 'USER_ID = "testuser"';
$VAR2 = '
';
$VAR3 = 'WRAP_COLUMN = "999"';
You are matching two lines at the time, and also uselessly capturing a newline. This would create false mismatches if you have an odd number of lines in your input. The last line would not match.
You will see that I have added the /g flag to allow your regex to be iterated over, which I think you intended. Otherwise it would just be an infinite loop.
[^\n]*? is a fancy way to say .*?, since period . matches any character except newline. The quantifier *? means match as short a string as possible. But since your string is anchored with ^ and \n that is redundant. It will match the same amount, regardless of your minimal match quantifier.
(\n) is not a very useful capture. We don't need to match a constant, we always know what a constant value is.
So this part of your regex really should be written
^(.*)\n
1: What does (.)*$ do?
Well, it captures several single characters at the end of a line. Lets try it out:
$ perl -lwe'$_ = "123456789"; /(.)*$/; print $1;'
9
It captures and overwrites several times until it finds the last match. It is a quite impressively inoperational regex. It does match, after a fashion, but it's hard to understand and predict. I.e.: You probably should not use it.
2: Is it correct to use /m modifier?
Yes, if you wish to use ^ and $ inside a multiline string to mean "match after a newline or beginning of string" (^), and "match before a newline or end of string" ($) respectively.
Is it necessary for this string? No, I will demonstrate a few options below.
3: Why doesn't the regex work as intended, i.e.: where is the mistake?
Since I don't know what your intention was, I don't know what your mistake is. The code adds tokens for odd line numbers, and a newline. And then discards even line numbers. What you probably want is to match each line, for which you really only need
/(.*)/g
So basically to match each line, you can just do
while ($token =~ /(.*)/g) {
You do need the /g modifier, otherwise it will be an infinite loop. With the redundant /m modifier it would be:
while ($token =~ /^(.*)$/mg) {
As solutions go, this is rudimentary. You can just split on newline to get the same result. You might consider these alternatives:
my %items;
while ($token =~ /(.+)\s+=\s+(.+)/g) { # match non-newline strings around =
$items{$1} = $2; # store match
}
print Dumper \%items;
# I would probably have done this:
# Hash version #2
my %items2 = map { split /\s+=\s+/ } # 2. split each line on the =
split /\n/, $token; # 1. split string on newline
print Dumper \%items2;
Both of these will produce:
$VAR1 = {
'ACCOUNT_CHANGED_T ' => '"1753690545"',
'USER_ID ' => '"testuser"',
'WRAP_COLUMN ' => '"999"',
'ACCOUNT_CHANGED ' => '"20250728081545Z"',
'CURRENT_TIME_T ' => '"1753863424"',
'INSTANCE ' => '"testing"',
'TEMPLATE_TIME_T ' => '"1753699621"',
'COMMON_NAME ' => '"User Test"'
};
TLDR: You overcomplicated the regex. (.*) is all that was needed.
.matches all characters except line breaks, regex101.com/r/igYTeu/1 - you'd need to add thesmodifier to make it match those as well, regex101.com/r/igYTeu/2undef $/? Your second capture group is always a newline, and there should only be one newline per line unless you are using file at once./mmulti-line mode for this since you're counting just the first 3 lines. Instead use.*in conjunction with the\Rline-break construct. No other modifiers. Only capture the second and third lines then./^.*\R(.*)\R(.*)/regex101.com/r/9k6bxo/1 . Also , these capture groups will always be defined() a valid check is on its length.