sunglant has asked for the wisdom of the Perl Monks concerning the following question:

I have been struggling with a problem for about 2 weeks now. all I need to do is add a sed call to a perl script. I have tried several of the tricks listed on perl monks and finally have given into asking for help.

sed -e 's#[^0-9]*\([0-9]\{3\}\)[^0-9]*\([0-9]\{3\}\)[^0-9]*\([0-9]\{4\}\)#(\1) \2-\3#' $FILE

all I need to do is add the above complex set to perl, when I attempt to run s2p I recieve a bunch of errors in the output code. As a perl novice I have little experience debugging something of this nature. I have attached the output. I would love it if someone could say BTW oneliner x will make this work, or here is how to set the system call. Thank you for any help Perl Novice.

s2p 's#[^0-9]*\([0-9]\{3\}\)[^0-9]*\([0-9]\{3\}\)[^0-9]*\([0-9]\{4\}\) +#(\1) \2-\3#' Having no space between pattern and following word is deprecated at (e +val 1) line 27. Bareword found where operator expected at (eval 1) line 27, near "s #\ +D*(\d{3})\D*(\d{3})\D*(\d{4})#(${1}) ${2}-${3}#s; $CondReg ||= $s; } EOS: if( $doPrint" (Might be a runaway multi-line $$ string starting on line 25) (Do you need to predeclare s?) Code: # prototypes sub openARGV(); sub getsARGV(;\$); sub eofARGV(); sub printQ(); # Run: the sed loop reading input and applying the script # sub Run(){ my( $h, $icnt, $s, $n ); # hack (not unbreakable :-/) to avoid // matching an empty string my $z = "\000"; $z =~ /$z/; # Initialize. openARGV(); $Hold = ''; $CondReg = 0; $doPrint = $doAutoPrint; CYCLE: while( getsARGV() ){ chomp(); $CondReg = 0; # cleared on t BOS:; # s#[^0-9]*\([0-9]\{3\}\)[^0-9]*\([0-9]\{3\}\)[^0-9]*\([0-9]\{4\}\)#(\ +1) \2-\3# { $s = s #\D*(\d{3})\D*(\d{3})\D*(\d{4})#(${1}) ${2}-${3}#s; $CondReg ||= $s; } EOS: if( $doPrint ){ print $_, "\n"; } else { $doPrint = $doAutoPrint; } printQ() if @Q; + } + + exit( 0 ); + { + + # openARGV: open 1st input file + # + sub openARGV(){ + unshift( @ARGV, '-' ) unless @ARGV; + my $file = shift( @ARGV ); + open( ARG, "<$file" ) + || die( "$0: can't open $file for reading ($!)\n" ); $isEOF = 0; } # getsARGV: Read another input line into argument (default: $_). # Move on to next input file, and reset EOF flag $isEOF. sub getsARGV(;\$){ my $argref = @_ ? shift() : \$_; while( $isEOF || ! defined( $$argref = <ARG> ) ){ close( ARG ); return 0 unless @ARGV; my $file = shift( @ARGV ); open( ARG, "<$file" ) || die( "$0: can't open $file for reading ($!)\n" ); $isEOF = 0; } 1; } # eofARGV: end-of-file test # sub eofARGV(){ return @ARGV == 0 && ( $isEOF = eof( ARG ) ); } # makeHandle: Generates another file handle for some file (given by it +s path) # to be written due to a w command or an s command's w fla +g. sub makeHandle($){ my( $path ) = @_; my $handle; if( ! exists( $wFiles{$path} ) || $wFiles{$path} eq '' ){ $handle = $wFiles{$path} = gensym(); if( $doOpenWrite ){ if( ! open( $handle, ">$path" ) ){ die( "$0: can't open $path for writing: ($!)\n" ); } } } else { $handle = $wFiles{$path}; } return $handle; } # printQ: Print queued output which is either a string or a reference # to a pathname. sub printQ(){ for my $q ( @Q ){ if( ref( $q ) ){ # flush open w files so that reading this file gets it all if( exists( $wFiles{$$q} ) && $wFiles{$$q} ne '' ){ open( $wFiles{$$q}, ">>$$q" ); } # copy file to stdout: slow, but safe if( open( RF, "<$$q" ) ){ while( defined( my $line = <RF> ) ){ print $line; } close( RF ); } } else { print $q; } } undef( @Q ); } s2p: internal error - generated incorrect Perl code: syntax error at ( +eval 1) line 27, near "s #\D*(\d{3})\D*(\d{3})\D*(\d{4})#(${1}) ${2}- +${3}#s; $CondReg ||= $s; } EOS: if( $doPrint " syntax error at (eval 1) line 29, near "} else" syntax error at (eval 1) line 36, near "; }" syntax error at (eval 1) line 46, near "; }" Can't use global @_ in "my" at (eval 1) line 51, near "= @_ " Global symbol "$argref" requires explicit package name at (eval 1) lin +e 52. syntax error at (eval 1) line 61, near "; }" Can't use global @_ in "my" at (eval 1) line 72, near "= @_" syntax error at (eval 1) line 85, near "; }" Missing right curly or square bracket at (eval 1) line 111, at end of +line (eval 1) has too many errors.

Replies are listed 'Best First'.
Re: Running complex sed from perl
by roboticus (Chancellor) on Dec 01, 2013 at 17:27 UTC

    sunglant:

    If you had a complex sed script that you were converting to perl, then you may want to use s2p. But your sed script is simply doing a global search and replace. It also looks like shell quoting may be muddying the waters.

    In general, if you see a sed invocation like sed -e 's#pattern#replacement#', then your perl code should look something like[1]:

    # Standard setup stuff and file handle opening goes here while (<THE_FILE_HANDLE>) { s#pattern#replacement#; }

    So a simple example could be:

    #!/usr/bin/perl use strict; use warnings; # Get and open the input and output files my $INFname = shift; open my $INFH, '<', $INFName or die "Can't open '$INFName' for input: +$!"; my $OUTFName = shift or die "Missing filename(s)!\n"; open my $OUFH, '>', $OUTFName or die "Can't open '$OUTFName' for outpu +t: $!"; # Do the search and replace while (<$INFH>) { s/foo/bar/g; print $OUFH $_; }

    So all you really need to do is pick apart your regular expression, make sure you can express it in perl without getting any quoting bits mixed in, and you should be good to go.

    Notes:

    [1] You can even do it on the command line like the sed example, but I don't generally use one-liners.

    [2] The code is untested, and you'll probably want to modify it in any case.

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

Re: Running complex sed from perl
by wazat (Monk) on Dec 01, 2013 at 18:39 UTC

    Assuming the regex conversion was correct. Would the following serve?

    #!/bin/perl -p s#\D*(\d{3})\D*(\d{3})\D*(\d{4})#(${1}) ${2}-${3}#s;

    sample input

    adhjfgl 123ab786YT789034 asdf123ab786YT789034 (123) 786-789034 123ab786YT7890bc 1234567890

    output

    adhjfgl (123) 786-789034 (123) 786-789034 (123) 786-789034 (123) 786-7890bc (123) 456-7890

      here is the code that I used, to test based on the the information given, I used a perl one liner to validate it works without a hitch

       perl -pi.back -e 's#\D*(\d{3})\D*(\d{3})\D*(\d{4})#(${1}) ${2}-${3}#s;' clients.txt

      Now of course, I realized the flaw in my thinking, and several components of the script are completely written on Linux systems, the flaw of course is that when testing the perl script on a windows system without say cgywin and only strawberry or absolute perl calls for awk and sed will not work. Luckly at this point there is only a single awk command left. All it does is place double quotes around each line in the output.txt file so that the perl script can then modify the other lines with the necessary formating. If I can figure out how to get double quotes at the begining and end of each line, then when its formated it can be converted into a CSV file and imported into a DB.

        If I can figure out how to get double quotes at the begining and end of each line...

        There are several ways to do that.

        # if the current line is in $_ s/^|$/"/g; # if the current line is in $line $line =~ s/^|$/"/g; # or with [doc://substr] substr $_, 0, 0, '"'; substr $_, length $_, 0, '"'; # but it is simpler just to append a " $_ .= '"'; # or even $_ = '"' .$_ . '"';
        perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'

        Hi sunglant,

        If I can figure out how to get double quotes at the begining and end of each line, then when its formated it can be converted into a CSV file and imported into a DB.
        I really don't know why you are trying to code in sed and awk using perl.
        Since perl can do want you want why not write all your script in perl altogether? Then using a module like Text::CSV or Text::CSV_XS you can get your dataset in csv then getting all of that into your preferred DB still using perl.

        If you tell me, I'll forget.
        If you show me, I'll remember.
        if you involve me, I'll understand.
        --- Author unknown to me

        There is more than one way to do it. You could add double quotes via additional search and replace.

        perl -pi.back -e 's#\D*(\d{3})\D*(\d{3})\D*(\d{4})#(${1}) ${2}-${3}#s; + s#^#""; s#$#"#' clients.txt

      That works beautifully, I am more than thank full. Which lead to a different problem in the script, now my awk line isn't working. I assume the issue is that the system I am working on doesn't have cgywin installed. Anyone have a quick perl one liner to put quotes at the begining of a line then the end? thank you all very much, to me being a novice with varying languages and limited scripting skills leaves alot of this up to being simply black majik, and Perl has many functions in blackboxes which I don't fully understand.

      Thank you, I will run some testing this evening, and then will respond again.

Re: Running complex sed from perl
by educated_foo (Vicar) on Dec 01, 2013 at 19:08 UTC
    If you change your delimiter from "#" to "!", it should work fine.