3

How can I print a string (single-quoted) containing double-backslash \\ characters as is without making Perl somehow interpolating it to single-slash \? I don't want to alter the string by adding more escape characters also.

my $string1 = 'a\\\b';
print $string1; #prints 'a\b'

my $string1 = 'a\\\\b';
    #I know I can alter the string to escape each backslash
    #but I want to keep string as is.
print $string1; #prints 'a\\b'

#I can also use single-quoted here document
#but unfortunately this would make my code syntactically look horrible.
my $string1 = <<'EOF';
a\\b
EOF
print $string1; #prints a\\b, with newline that could be removed with chomp
Omar
  • 6,681
  • 5
  • 21
  • 36
  • Let me guess... dealing with Windows file paths? – Schwern Feb 19 '17 at 19:31
  • No I'm passing single-quoted-strings to subroutines and those strings are containing double-backslashes. – Omar Feb 19 '17 at 19:33
  • Oh. Could you give an example? You shouldn't have to escape double quotes inside single quotes. `'She said, "you don't have to escape double quotes in single quotes."'` is fine. So is using `qq[]` if you want interpolation but don't want to escape double quotes. – Schwern Feb 19 '17 at 19:34
  • Sorry: edited the comment. I meant double-backslashes instead of double-quotes – Omar Feb 19 '17 at 19:36
  • The only places that a double backslash is interpreted as a single backslash is within string literals in your program. If they are read from a file or contained in a variable then they are left as they are. Do you really need your string literals to be in a specific form? Could you explain why? – Borodin Feb 19 '17 at 20:48

3 Answers3

10

The only quoting construct in Perl that doesn't interpret backslashes at all is the single-quoted here document:

my $string1 = <<'EOF';
a\\\b
EOF
print $string1; # Prints a\\\b, with newline

Because here-docs are line-based, it's unavoidable that you will get a newline at the end of your string, but you can remove it with chomp.

Other techniques are simply to live with it and backslash your strings correctly (for small amounts of data), or to put them in a __DATA__ section or an external file (for large amounts of data).

hobbs
  • 223,387
  • 19
  • 210
  • 288
  • 1
    I did not know that! – Schwern Feb 19 '17 at 19:30
  • Single-quoted here document solution on each string I have would make my code syntactically look horrible. – Omar Feb 19 '17 at 19:42
  • 1
    @Omar well, I'm just laying out the facts. You can backslash your backslashes, you can use heredocs, or you can keep these paths somewhere other than in a Perl source file. To the best of my knowledge there aren't any other reasonable options, so pick the one you dislike least :) – hobbs Feb 19 '17 at 19:52
  • 1
    @hobbs Option 4: Write XS module, hook into parser, write own quoting operator. – melpomene Feb 19 '17 at 20:13
  • 1
    @melpomene hmm, not too crazy. Maybe tonight I will try to write a raw-quote module. – hobbs Feb 19 '17 at 20:37
  • 3
    @melpomene https://github.com/arodland/Syntax-Feature-RawQuote — `perl -Msyntax=raw_quote -le 'print r\`a\\b\\c\`' ` – hobbs Feb 20 '17 at 01:51
7

If you are mildly crazy, and like the idea of using experimental software that mucks about with perl's internals to improve the aesthetics of your code, you can use the Syntax::Keyword::RawQuote module, on CPAN since this morning.

use syntax 'raw_quote';
my $string1 = r'a\\\b';
print $string1; # prints 'a\\\b'

Thanks to @melpomene for the inspiration.

hobbs
  • 223,387
  • 19
  • 210
  • 288
0

Since the backslash interpolation happens in string literals, perhaps you could declare your literals using some other arbitrary symbol, then substitute them for something else later.

my $string = 'a!!!b';
$string =~ s{!}{\\}g;
print $string; #prints 'a\\\b'

Of course it doesn't have to be !, any symbol that does not conflict with a normal character in the string will do. You said you need to make a number of strings, so you could put the substitution in a function

sub bs {
    $_[0] =~ s{!}{\\}gr
}

my $string = 'a!!!b';
print bs($string); #prints 'a\\\b'

P.S. That function uses the non-destructive substitution modifier /r introduced in v5.14. If you are using an older version, then the function would need to be written like this

sub bs {
    $_[0] =~ s{!}{\\}g;
    return $_[0];
}

Or if you like something more readable

sub bs {
    my $str = shift;
    $str =~ s{!}{\\}g;
    return $str;
}
elcaro
  • 2,227
  • 13
  • 15