-1

I have this sample string, containing 2 backslashes. Please don't ask me for the source of the string, it is just a sample string.

my $string = "use Ppppp\\Ppppp;";
print $string;

Both, double quotes or quotes will print

use Ppppp\Ppppp;

Using

my $string = "\Quse Ppppp\\Ppppp;\E";
print $string;

will print

use\ Ppppp\\Ppppp\;

adding those extra backslashes to the output.

Is there a simple solution in perl to display the string "literally", without modifying the string like adding extra backslashes to escape?

Claude
  • 171
  • 10
  • 1
    Do you want to escape __only__ special characters and not whitespace? – Corion Jan 22 '19 at 18:42
  • 2
    `\Q\E` which is internally just an interpolated form of the [quotemeta](https://perldoc.pl/functions/quotemeta) function escapes all ASCII characters other than `[A-Za-z_0-9]`, as documented. Notably this means whitespace will be escaped. What exactly do you want to escape? – Grinnz Jan 22 '19 at 18:51
  • I want the string (like example already provided) to be printed exactly with all backslashes or other special characters. I don't understand why \Q\E add those extra backslashes trying to escape space and ; – Claude Jan 22 '19 at 18:55
  • 2
    Because that's its purpose, to escape all other than the class @Grinnz spelled out. Since you don't want _all_ that escaped then you'd need to specify the exact list, of either: what you want escaped (and escape those explicitly) or of what you _don't_ want escaped, so you can preserve them (see my answer). – zdim Jan 22 '19 at 18:58
  • 1
    quotemeta is designed as a general escaping mechanism. It cannot know what characters will be "special" for whatever you are using it for - space characters and semicolons are both special in certain contexts (shells, SQL - though there's better options than quotemeta for either of those specifically). Hence why I asked what *exactly* you want to escape. – Grinnz Jan 22 '19 at 18:59
  • zdim, did you check my question carefully? Well, I have this string "use Proxy\\Proxy;" Tell me how to display it exactly, including backslashes. – Claude Jan 22 '19 at 19:00
  • 2
    Claude: No, you have that string in your source code. Perl parses backslashes in strings always so that two backslashes represent a single backslash in the value. If you want two backslashes, you need to write four backslashes in your source code. – Corion Jan 22 '19 at 19:02
  • 2
    quotemeta is the wrong tool for this job, you need to construct it properly, for example like `my $str = 'use Proxy\\\\Proxy;';` - you need to escape backslashes to include them in string literals in Perl, the only exception being in [single-quoted here-docs](https://perldoc.pl/perlop#Single-Quotes), or in single-quoted strings when not followed by a single quote or another backslash. – Grinnz Jan 22 '19 at 19:03
  • 1
    @Claude Yes, I did look at your question carefully. The problem is that it shows only one example string; what else may you have? Did you see my answer, and the comment above, carefully? In order to process correctly more than just that one example you need to know what _exactly_ you want unaffected. If you merely want the string to be printed literally as is then that's a little different. Is that what you need? – zdim Jan 22 '19 at 19:07
  • Strings comes exactly as they are, I don't want to modify the strings adding extra escapes with "\". I only want to have them printed exactly, I need a way to automatically escape everything in the string, without editing the string. Just think to thousands of special strings with all kind of special characters. – Claude Jan 22 '19 at 19:08
  • 1
    If you write it in your source code like that, it is not exactly as it is, because you created a string with only one backslash. If it's coming from external input such as a filehandle, or you put it in a single-quoted here-doc as mentioned in the above comment, then it will be exactly as it appears. – Grinnz Jan 22 '19 at 19:09
  • OK, got it. The matter got confused because of your use of the word _escape_ -- apparently you _don't want_ to escape things but simply want a string printed literally. The problem there is precisely the double backslash itself – zdim Jan 22 '19 at 19:09
  • Yes, zdim. I need a way to only print the string literally. Tha's just a sample string, I have thousands to process. \Q\E should do the job, but insert those extra "\" and I don't want that. – Claude Jan 22 '19 at 19:09
  • 2
    @Claude No, the `\Q\E` won't do what you want; their job _is_ to escape things -- what normally means _to add backslashes_. – zdim Jan 22 '19 at 19:10
  • 2
    quotemeta is inappropriate for this task because by the time it is run, the backslashes you wanted are already gone. Are your strings all written directly in the source code like your example, or are they coming from somewhere else? – Grinnz Jan 22 '19 at 19:12
  • @Claude The primary purpose of `\Q\E` is to escape any characters that might be special to regular expressions. You seem to want some other kind of escaping scheme, so you'd have to say what for, and give a *complete* list of what you consider *"all special characters including backslash"*. Maybe you're looking for something like `pp` from [`Data::Dump`](https://metacpan.org/pod/Data::Dump)? Also, it's important to note that the Perl string `"use Proxy\\Proxy;"` only contains *one* backslash. – haukex Jan 22 '19 at 19:21
  • @Claude To summarize it: you want your strings printed literally (so _not_ "escaped" or "quoted"), which is easy -- except for the double backslash combination, as stated by multiple people above. So the key question is: how does the data -- those strings -- come to your program? – zdim Jan 22 '19 at 19:21
  • There is hash I must match against, but I didn't want to make the question more complicated.. Using my example, the hash key is "use Proxy\\Proxy;". If I compare a string coming from an external text, it will not match, because, in this example, the string is interpreted as "use Proxy\Proxy;". That's why I need a way for a string to remain exactly the same. – Claude Jan 22 '19 at 19:22
  • @Claude Again: please, how does data come into your program? From a file? – zdim Jan 22 '19 at 19:23
  • Yes, the problem is with that double backslash combination. – Claude Jan 22 '19 at 19:23
  • zdim, I don't think it has any importance. I'm looking to print "\use Proxy\\Proxy;" without adding extra backslashes to the string. That's all. – Claude Jan 22 '19 at 19:25
  • @Claude What does the hash key look like when you dump the hash with a module such as [`Data::Dump`](https://metacpan.org/pod/Data::Dump)? If it shows `"use Proxy\\Proxy;"`, then again, that string only contains one backslash character. If it shows `"use Proxy\\\\Proxy;"`, then the string does indeed contain two backslash characters. You need to do the same check on the string you're looking for. – haukex Jan 22 '19 at 19:27
  • 4
    @Claude Re "_I don't think it has any importance_" -- alright, good luck – zdim Jan 22 '19 at 19:28
  • What importance it may have? Sincerely.... Let say I have this string "use Proxy\\Proxy;" from some source and I want to print it exactly as it is. Thank you anyway for your advice. I found this https://stackoverflow.com/questions/42331653/how-can-i-prevent-perl-from-interpreting-double-backslash-as-single-backslash-ch I didn't thought there is no simple solution for this. – Claude Jan 22 '19 at 19:34
  • 2
    The importance is that if you write `"use Proxy\\Proxy;"` literally in your program, you have created the string `use Proxy\Proxy;`, because the Perl parser treats backslashes this way in quoted string literals, so this is what your string will contain; but if you read from a file the text `use Proxy\\Proxy;` into a string, you will have exactly that text. – Grinnz Jan 22 '19 at 19:37
  • I don't know, I thought my example was very clear. I have a string, no importance where it is coming from and I want to print it exactly, without modifying the string. It looks like perl doesn't have a simple solution to am I wrong? – Claude Jan 22 '19 at 19:42
  • @Claude The importance is that the people trying to help you are asking for more information to help you solve your issue. I suggest you take the time to read all the comments again and provide the info requested by editing your question. Also have a look at [MCVE](https://stackoverflow.com/help/mcve). BTW, the way to *"print it exactly as it is"* is [`print`](http://perldoc.perl.org/functions/print.html). Like Grinnz, I think the confusion here, and what everyone has been trying to say, might be that when you write `"use Proxy\\Proxy;"` in your Perl source, that string only has one backslash. – haukex Jan 22 '19 at 19:42
  • 3
    Where it comes from determines how to solve your problem, thus it is important. – Grinnz Jan 22 '19 at 19:43
  • 1
    @Claude You are wrong. The way to print a string as-is is `print`. – melpomene Jan 22 '19 at 19:44
  • 2
    "*I have this sample string, containing 2 backslashes.*" No, you don't. As explained in the comments above, you have a string that contains a single backslash. `print` only prints what's there in the string. It does no extra interpretation. – melpomene Jan 22 '19 at 19:53
  • I have updated the question. – Claude Jan 22 '19 at 19:55
  • 2
    "Please don't ask me for the source of the string, it is just a sample string." - no, the source really matters. If the source is your source code, there is basically no way around manually doubling up all the backslashes in your source code. If the string comes from elsewhere, Perl does display the string as is. – Corion Jan 22 '19 at 19:58
  • I suppose you guys are right with the importance of the source. Thank you for helping me to understand this situation. In this case, my live script should work, because the source of strings is a file. I don't have yet a final version, so I can test correctly. After checking the other topic, it seems there isn't an easy way in perl to prevent interpreting double-backslash as a single backslash. – Claude Jan 22 '19 at 20:13

1 Answers1

3

I have this sample string, containing 2 backslashes. ...

my $string = "use Ppppp\\Ppppp;";

Sorry, but you're mistaken - that string only contains one backslash*, as \\ is a escape sequence in double-quoted (and single-quoted) strings that produces a single backslash. See also "Quote and Quote-like Operators" in perlop. If your string really does contain two backslashes, then you need to write "use Ppppp\\\\Ppppp;", or use a heredoc, as in:

chomp( my $string = <<'ENDSTR' );
use Ppppp\\Ppppp;
ENDSTR

If you want the string output as valid Perl source code (using its escaping), then you can use one of several options:

my $string = "use Ppppp\\Ppppp;";
# option 1
use Data::Dumper;
$Data::Dumper::Useqq=1;
$Data::Dumper::Terse=1;
print Dumper($string);
# option 2
use Data::Dump;
dd $string;
# option 3
use B;
print B::perlstring($string);

Each one of these will print "use Ppppp\\Ppppp;". (There are of course other modules available too. Personally I like Data::Dump. Data::Dumper is a core module.)

Using one of these modules is also the best way to verify what your $string variable really contains.

If that still doesn't fit your needs: A previous edit of your question said "How can I escape correctly all special characters including backslash?" - you'd have to specify a full list of which characters you consider special. You could do something like this, for example:

use 5.014; # for s///r
my $string = "use Ppppp\\Ppppp;";
print $string=~s/(?=[\\])/\\/gr;

That'll print $string with backslashes doubled, without modifying $string. You can also add more characters to the regex character class to add backslashes in front of those characters as well.

* Update: So I don't sound too pedantic here: of course the Perl source code contains two backslashes. But there is a difference between the literal source code and what the Perl string ends up containing, the same way that the string "Foo\nBar" contains a newline character instead of the two literal characters \ and n.

For the sake of completeness, as already discussed in the comments: \Q\E (aka quotemeta) is primarily meant for escaping any special characters that may be special to regular expressions (all ASCII characters not matching /[A-Za-z_0-9]/), which is why it is also escaping the spaces and semicolon.

Since you mention external files: If you are reading a line such as use Ppppp\\Ppppp; from an external file, then the Perl string will contain two backslashes, and if you print it, it will also show two backslashes. But if you wanted to represent that string as Perl source code, you have to write "use Ppppp\\\\Ppppp;" (or use one of the other methods from the question you linked to).

haukex
  • 2,973
  • 9
  • 21
  • Thanks for your reply. Your advice (and others) helped me understand how things are with double backslash. – Claude Jan 22 '19 at 20:26
  • Re "*Sorry, but you're mistaken - that string only contains one backslash*", Better wording: "It's actually the *string literal* that has two backslashes; the *string* it produces only has one." – ikegami Jan 23 '19 at 01:32