in reply to Re^3: How do I display only matches (updated)
in thread (SOLVED) How do I display only matches

although I see no need to stringize "$line" when $line is already a string read from a file

Correct, in this case it doesn't matter. However since print can take an optional file handle print $fh $data there are some cases where print can be confused about what the first token means (filehandle or something to print to a filehandle). I coded what I knew would work rather than the minimal formulation. I didn't take any time worrying about this detail. My main point as you observed was: "make the regex as complicated as it needs to be, but no more"!

I will point out that the Regex character "$" solves the platform specific line ending \r\n vs \n vs no line ending problem. "$" matches the the end of the string (or before newline at the end of the string; or before any newline if /m is used). I think \Z is the same. So /abc$/ matches lines ending in abc whether there is a line ending there or not.

Replies are listed 'Best First'.
Re^5: How do I display only matches
by haukex (Archbishop) on Sep 25, 2019 at 17:20 UTC
    I will point out that the Regex character "$" solves the platform specific line ending \r\n vs \n vs no line ending problem.

    No, $ and \Z only work with \n, not \r:

    use warnings; use strict; use Data::Dump; for my $str ( "foo", "foo\n", "foo\r\n" ) { dd $str, scalar $str=~/o$/; } __END__ ("foo", 1) ("foo\n", 1) ("foo\r\n", "")

    Output is the same on Windows and *NIX.

      I ran your code on my Windows machine and got the same results. Hooray! This is exactly as expected!!!

      I copied the text for "$" verbatim from the Perl regex docs. Normally that is good enough. However in this case I see that some further "yeah but" explanation is required!

      Problem 1: What "\n" is can be both platform and sometimes context dependent! If I write a "\n" on my Windows machine, that means 2 characters: <CR><LF> (Carriage Return, Line Feed). So when you write "foo\r\n", on Windows that means <CR><CR><LF>. This extra <CR> means that the line doesn't end in "\n", <CR><LF> (Carriage Return, Line Feed). There is indeed something else between the "o" and the line ending and your regex doesn't match - this is correct behavior.

      You may not know this (many folks don't), but no matter what the OS platform, when writing to a network socket, "\n" means <CR><LF>. <CR><LF> is the network standard for line endings. So, yes, even on Unix, a write to network socket will be <CR><LF>, while a write to a disk file will be just <LF>. Windows uses the network standard for disk writes - so everywhere on Windows \n means the 2 characters <CR><LF>.

      Problem 2: Not every cross platform case and every platform direction is handled automatically by Perl. If you are on a single platform, then "$" will work as the docs describe as will chomp(). I have one program that needs to work on: a) old Mac "\n" means <CR> in files, b)Windows "\n" means <CR><LF> in files, c)Unix, "\n" means <LF> in files. When I write code that has to work with all 3 platforms, I use regex instead of chomp to delete the line endings. s/\s*$//; deletes all whitespace at the end of the line (including line endings like <CR><LF> which are considered "whitespace".

      Another thought: I told the OP that there was no need to "chomp" if you are just going to add the line ending back in. That is true as long as you are processing a file and writing a file for the same platform. There are some cases where you'd "chomp" and then print "$_\n" to change the line endings.

      I hope this post adds more clarity to the issue. But it probably raises more "yeah, but what if..." questions than it answers. This is all more complex than our OP asked about. I suggest starting a new thread if there is interest in discussing the "dirty details".

      Update: To allow for this <CR><CR><LF> situation:

      use warnings; use strict; use Data::Dump; for my $str ( "foo", "foo\n", "foo\r\n" ) { dd $str, scalar $str=~/o\s*$/; } __END__ ("foo", 1) ("foo\n", 1) ("foo\r\n", 1)
        If I write a "\n" on my Windows machine, that means 2 characters: <CR><LF> (Carriage Return, Line Feed). So when you write "foo\r\n", on Windows that means <CR><CR><LF>. This extra <CR> means that the line doesn't end in "\n", <CR><LF> (Carriage Return, Line Feed). There is indeed something else between the "o" and the line ending and your regex doesn't match

        I've seen you say something along these lines a couple times before, and I'm sorry, but it's flat out wrong.

        C:\>perl -wMstrict -MDevel::Peek -e "my$x=qq{\n};Dump($x)" SV = PV(0x32aa98) at 0x577ef8 REFCNT = 1 FLAGS = (POK,IsCOW,pPOK) PV = 0x556ba4 "\n"\0 CUR = 1 LEN = 10 COW_REFCNT = 1

        Note CUR = 1 - there is only one character in that string, not two. I dimly remember that there might have been some builds of Perl for Windows back in the 90's that may have tried to handle it differently, and I remember being confused by this early on as well, but for a long time now, on both Windows and *NIX, \n is LF, and that's what Perl uses internally. The difference is that on Windows the :crlf layer translates that on input and output, but it doesn't change the internal representation, how regexes work, or the default $/ - even on Windows, it's "\n", one byte, "\x0A".

        I suggest you take the time to read Newlines in perlport and PerlIO.

        I copied the text for "$" verbatim from the Perl regex docs.

        Where in the Perl docs does it say $ matches before \r?

        You may not know this (many folks don't), but no matter what the OS platform, when writing to a network socket, "\n" means <CR><LF>. ... So, yes, even on Unix, a write to network socket will be <CR><LF>, while a write to a disk file will be just <LF>.

        The way you worded this actually annoyed me enough that I double-checked my knowledge on this.

        serv.pl:

        use warnings; use strict; use IO::Socket::INET; use Devel::Peek; my $sock = IO::Socket::INET->new(Listen => 5, LocalPort => 9000, LocalAddr => 'localhost', Proto => 'tcp') or die $!; my $cli = $sock->accept(); $cli->read(my $in, 5); Dump($in);

        cli.pl:

        use warnings; use strict; use IO::Socket::INET; my $sock = IO::Socket::INET->new("localhost:9000") or die $!; print $sock "foo\n\0\0";

        Output of serv.pl:

        SV = PV(0x573aeb89cfe0) at 0x573aeb8e2b50 REFCNT = 1 FLAGS = (POK,pPOK) PV = 0x573aeb8ed890 "foo\n\0"\0 CUR = 5 LEN = 10

        And, a Wireshark capture of the raw packet on the wire shows:

        66:6f:6f:0a:00:00

        On Linux and on Windows. You're wrong on both of those counts as well. (You can add binmode $sock, ':crlf'; to the client, and it'll be 0d0a on both platforms, as expected.)

        I hope this post adds more clarity to the issue.

        No, it spreads false and confusing information.