Confused about string terminator in Perl - perl

I read several postings here about getting the error message -
can't find string terminator "" anywhere before EOF ...
can't find string terminator "'" anywhere before EOF ...
I don't think I really understand it, although the take-home message is not to use single quotes.
So okay, I will try NOT to use single quotes. But still, if possible, could someone help me understand the differences between the two scripts, in terms of how Perl sees them differently
#!/usr/bin/perl -w
#backwhacking
print "c:\\WINNT\\Profiles\\\n";
print 'c:\WINNT\Profiles\ ', "\n";
#!/usr/bin/perl -w
#backwhacking
print "c:\\WINNT\\Profiles\\\n";
print 'c:\WINNT\Profiles\', "\n";
The first script runs fine with the output
c:\WINNT\Profiles
c:\WINNT\Profiles
whereas the second script gave me the same error code about not able to find script terminator "'"
And is there any "reason" why Perl programming needs to distinguish between with or without a space with single quotes? Sorry, but it seems somewhat trivial to a non-computer science person.

' style quotes use backslash to escape ' character.
So: print '\''; will print ' character, and not \' string.
when you print 'whatever\ ' - it will print >whatever < - with space at the end. But if you do:
print 'whatever \'
this is not terminated string, because the backslash escapes '. So the following , "\n"; are treated as part of '' string.

Related

How do I match a string ending in whitespace using grep in Perl?

I want to call grep in a Perl script like so:
my $line = `grep "^$name\b" $inputFile`;
When I run the actual grep command in the terminal, it returns what is expected, but when I include this line in my script, nothing is returned.
If I replace the \b with a \s, it complains with "Unrecognized escape \s passed through at test.pl line 50."
I've already looked at how to use grep to match with either whitespace or newline, but it doesn't have specifics to why my script isn't returning the expected.
How do I properly include the \b or \s in the command in Perl?
you have to escape the '\' use grep \\b
You don't use backticks -- you write it in Perl
my $name = 'xyz';
my $line;
while ( <> ) {
next unless /^$name\b/;
$line = $_;
last;
}
This would be likely to be much less clumsy if the context of the test were known. You may need to escape the contents of $name if you wish to pass regex metacharacters through

Preserving backslashes in Perl strings

Is there a way in Perl to preserve and print all backslashes in a string variable?
For example:
$str = 'a\\b';
The output is
a\b
but I need
a\\b
The problem is can't process the string in any way to escape the backslashes because
I have to read complex regular expressions from a database and don't know in which combination and number they appear and have to print them exactly as they are on a web page.
I tried with template toolkit and html and html_entity filters. The only way it works so far is to use a single quoted here document:
print <<'XYZ';
a\\b
XYZ
But then I can't interpolate variables which makes this solution useless.
I tried to write a string to a web page, into file and on the shell, but no luck, always one backslash disappears. Maybe I am totally on the wrong track, but what is the correct way to print complex regular expressions including backslashes in all combinations and numbers without any changes?
In other words:
I have a database containing hundreds of regular expressions as string data. I want to read them with perl and print them on a web page exatly as they are in the database.
There are all the time changes to these regular expressions by many administrators so I don't know in advance how and what to escape.
A typical example would look like this:
'C:\\test\\file \S+'
but it could change the next day to
'\S+ C:\\test\\file'
Maybe a correct conclusion would be to escape every backslash exactly one time no matter in which combination and in which number it appears? This would mean it works to double them up. Then the problem isn't as big as I feared. I tested it on the bash and it works with two and even three backslashes in a row (4 backslaches print 2 ones and 6 backslashes print 3 ones).
The backslash only has significance to Perl when it occurs in Perl source code, e.g.: your assignment of a literal string to a variable:
my $str = 'a\\b';
However, if you read data from a file (or a database or socket etc) any backslashes in the data you read will be preserved without you needing to take any special steps.
my $str = 'a\\b';
print $str;
This prints a\\b.
Use
my $str = 'a\\\\b';
instead
It's a PITA, but you will just have to double up the backslashes, e.g.
a\\\\b
Otherwise, you could store the backslash in another variable, and interpolate that.
The minimum to get two slashes is (unfortunately) three slashes:
use 5.016;
my $a = 'a\\\b';
say $a;
The problem I tried to solve does not exist. I confused initializing a string directly in the code with using the html forms. Using a string inside the code preserving all backslashes is only possible either with a here document or by reading a textfile containing the string. But if I just use the html form on a web page to insert a string and use escapeHTML() from the CGI module it takes care of all and you can insert the most wired combinations of special characters. They all get displayed and preserved exactly as inserted. So I should have started directly with html and database operations instead of trying to examine things first
by using strings directly in the code. Anyway, thanks for your help.
You can use the following regular expression to form your string correctly:
my $str = 'a\\b';
$str =~ s/\\/\\\\/g;
print "$str\n";
This prints a\\b.
EDIT:
You can use non-interpolating here-document instead:
my $str = <<'EOF';
a\\b
EOF
print "$str\n";
This still prints a\\b.
Grant's answer provided the hint I needed. Some of the other answers did not match Perl's operation on my system so ...
#!/usr/bin/perl
use warnings;
use strict;
my $var = 'content';
print "\'\"\N{U+0050}\\\\\\$var\n";
print <<END;
\'\"\N{U+0050}\\\\\\$var\n
END
print '\'\"\N{U+0050}\\\\\\$var\n'.$/;
my $str = '\'\"\N{U+0050}\\\\\\$var\n';
print $str.$/;
print #ARGV;
print $/;
Called from bash ... using the bash means of escaping in quotes which changes \' to '\''.
jamie#debian:~$ ./ft.pl '\'\''\"\N{U+0050}\\\\\\$var\n'
'"P\\\content
'"P\\\content
'\"\N{U+0050}\\\$var\n
'\"\N{U+0050}\\\$var\n
\'\"\N{U+0050}\\\\\\$var\n
The final line, with six backslashes in the middle, was what I had expected. Reality differed.
So:
"in here \" is interpolated
in HEREDOC \ is interpolated
'in single quotes only \' is interpolated and only for \ and ' (are there more?)
my $str = 'same limited \ interpolation';
perl.pl 'escape using bash rules' with #ARGV is not interpolated

How to combine two lines together using Perl?

How to combine two lines together using Perl? I'm trying to combine these two lines using a Perl regular expression:
__Data__
test1 - results
dkdkdkdkdkd
I would like the output to be like this:
__Data__
test1 - results dkdkdkdkdkd
I thought this would accomplish this but not working:
$_ =~ s/__Data__\n(test1.*)\n(.*)\n/__Data__\n$1 $2/smg;
If you have a multiline string:
s/__Data__\ntest1.*\K\n//g;
The /s modifier only makes the wildcard . match \n, so it will cause .* to slurp your newline and cause the match of \n to be displaced to the last place it occurs. Which, depending on your data, might be far off.
The /m modifier makes ^ and $ match inside the string at newlines, so not so useful. The \K escape preserves whatever comes before it, so you do not need to put it back afterwards.
If you have a single line string, for instance in a while loop:
while (<>) {
if (/^__Data__/) {
$_ .= <>; # add next line
chomp; # remove newline
$_ .= <>; # add third line
}
print;
}
There seems to be a problem with the setup of $_. When I run this script, I get the output I expect (and the output I think you'd expect). The main difference is that I've added a newline at the end of the replacement pattern in the substitute. The rest is cosmetic or test infrastructure.
Script
#!/usr/bin/env perl
use strict;
use warnings;
my $text = "__Data__\ntest1 - results\ndkdkdkdkdkd\n";
my $copy = $text;
$text =~ s/__Data__\n(test1.*)\n(.*)\n/__Data__\n$1 $2\n/smg;
print "<<$copy>>\n";
print "<<$text>>\n";
Output
<<__Data__
test1 - results
dkdkdkdkdkd
>>
<<__Data__
test1 - results dkdkdkdkdkd
>>
Note the use of << and >> to mark the ends of strings; it often helps when debugging. Use any symbols you like; just enclose your displayed text in such markers to help yourself debug what's going on.
(Tested with Perl 5.12.1 on RHEL 5 for x86/64, but I don't think the code is version or platform dependent.)

Perl Concat String Truncates Beginning of Line

I am running into a strange issue in perl that I can't seem to find an answer for.
I have a small script that will parse data from an external sorce (be it file, website, etc). Once the data has been parsed, it will then save it to a CSV file. However, the issue is when I am writing the file or printing to screen the data, it seems to be truncating the beginning of the string. I am using strict and warnings and I am not seeing any errors.
Here is an example:
print "Name: " . $name . "\n";
print "Type: " . $type. "\n";
print "Price: " . $price . "\n";
print "Count: " . $count . "\n";
It will return the following:
John
Blue
7.99
5
If I attempt to do it this way:
print "$name,$type,$price,$count\n";
I get the following as a result:
,7.99,5
I tried the following to see where the issue begins and get the following:
print "$name\n";
print "$name,$type\n";
print "$name,$type,$price\n";
print "$name,$type,$price,$count\n";
Results:
John
John,Blue
,7.99
,7.99,5
I am still learning perl, but can't seem to find out (maybe due to lack of knowledge) of what is causing this. I tried debugging the script, but I did not see any special character in the price variable that would cause this.
The string in $price ends with a Carriage Return. This is causing your terminal to move the cursor to the start of the line, causing the first two fields to be overwritten by the ones that follow.
You are probably reading a Windows text file on a unix box. Convert the file (using dos2unix, for example), or use s/\s+\z//; instead of chomp;.
If the CR made into the middle of a string, you could use s/\r//g;.
Per #Mat suggestion I ran the output through hexdump -C and found there was a carriage return (indicated by the hex value 0d). Using the code $price =~ s/\r//g; to remove the CR from the line of text fixed the problem.
Also, the input file was in Windows format not Unix, ran the command dos2unix to fix that.

Can't find string terminator "str" anywhere before EOF

Why I get this error?
use strict;
use warnings;
my $str = <<str;
88087 23/11/2010
35192 25/07/2010
B3J 5X9 17/08/2011
C8U 5L6 16/08/2011
F4Q 3B4 17/10/2010
D3X 9P4 11/05/2010
O7L 6Z8 28/02/2010
W8L 9P2 05/09/2010
str
print $str;
my #arr = split/\n/,$str;
foreach (#arr) {
my #tmp = split/\t/;
print "$tmp[1]\n";
}
You should not have a space here:
str
^
The heredoc terminator should be on a line by itself and should not have anything (not even space) surrounding it.
You can use diagnostics to get more verbose help on warning messages:
Can't find string terminator "str"
anywhere before EOF
(F) Perl strings can stretch over multiple lines. This message means
that the closing delimiter was omitted. Because bracketed quotes
count
nesting levels, the following is missing its final parenthesis:
print q(The character '(' starts a side comment.);
> If you're getting this error from a here-document, you may have included
unseen whitespace before or after your closing tag. A good programmer's
editor will have a way to help you find these characters.
Uncaught exception from user code:
Can't find string terminator "str" anywhere before EOF
Or Better Use Eclipse Perl Integration plug-in or Padre for editing your perl code.
It shows real-time syntax related errors.