Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

Selectively replacing characters inside a string

by markkawika (Monk)
on Jun 11, 2009 at 01:01 UTC ( [id://770487]=perlquestion: print w/replies, xml ) Need Help??

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

Hi, Monks!

I have a problem that I've come up with a reasonably nice solution for, but have been going over it in my head and wondering if it's the best solution.

I have a log file in which I want to hide file and path names. I want to preserve the appearance of a directory structure, so I do not want to hide the "/" characters that are used as directory separators.

The filename will always appear at most once per line, and will always appear inside of an easily identifiable section, like this: file="path/goes/here".

I would like to process that example so that the output looks like this: file="xxxx/xxxx/xxxx".

The solution that I came up with does exactly what I want. From the command line, I pipe it to this (this is on a Unix host):

... | perl -pe '1 while s|(file="[x/]*)[^x/"]|$1x|;'
I've been wondering if there is something simpler, like somehow being able to do s|[^/]|x|g on the text between file=" and ", but I haven't been able to figure out how.

Does anyone have any suggestions?

Replies are listed 'Best First'.
Re: Selectively replacing characters inside a string
by liverpole (Monsignor) on Jun 11, 2009 at 01:28 UTC
    Hi markkawika,

    The first thing that comes to mind if you want to do it with regexes is to first capture the quoted part, and then change it:

    use strict; use warnings; my $line = qq[file="path/goes/here"]; print "Line is '$line'\n"; if ($line =~ /^([^"]*)"([^"]*)"(.*)$/) { my ($prefix, $quoted, $suffix) = ($1, $2, $3); $quoted =~ s|[^/]|x|g; $line = qq[$prefix"$quoted"$suffix]; } print "Line is '$line'\n";

    Another way, if you're sure that the expression ends with the quoted expression, would be something very simple like:

    use strict; use warnings; my $line = qq[file="path/goes/here"]; print "Line is '$line'\n"; my @sections = split('"', $line); $sections[1] =~ s|[^/]|x|g; $line = join('"', @sections) . '"'; print "Line is '$line'\n";

    Both result in:

    Line is 'file="path/goes/here"' Line is 'file="xxxx/xxxx/xxxx"'

    Both are less simple than your solution, of course, but keep things within Perl, without resorting to using the shell.


    s''(q.S:$/9=(T1';s;(..)(..);$..=substr+crypt($1,$2),2,3;eg;print$..$/
Re: Selectively replacing characters inside a string
by johngg (Canon) on Jun 11, 2009 at 10:46 UTC

    Similar to AnomalousMonk's solution but using look-behind and -ahead assertions and tr with the "complement" flag.

    use strict; use warnings; open my $logFH, q{<}, \ <<EOD or die qq{open: << HEREDOC: $!\n}; 2009/06/09 10:11:12 read error: file="/path/to/file" reason: gone 2009/06/09 12:43:27 created: file="/path/to/file" EOD while( <$logFH> ) { s{(?<= file=" ) ( [^"]+ ) (?= " )} {do { my $cap = $1; $cap =~ tr{/}{x}c; $cap }}xeg; print; }

    The output.

    2009/06/09 10:11:12 read error: file="/xxxx/xx/xxxx" reason: gone 2009/06/09 12:43:27 created: file="/xxxx/xx/xxxx"

    I hope this is of interest.

    Cheers,

    JohnGG

      Thank you, JohnGG, that was exactly what I was trying to accomplish yesterday on my own, but you've done it much more succinctly than I did.
Re: Selectively replacing characters inside a string
by AnomalousMonk (Archbishop) on Jun 11, 2009 at 05:15 UTC
    It's also possible to use nested substitutions (I've use single-quotes instead of double-quotes to avoid the WinNoyance® of escaping a bunch of "s):
    >perl -wMstrict -le "for my $str (@ARGV) { print $str; $str =~ s{ (' [^']* ') } { (my $x = $1) =~ s{ [^'/] }{x}xmsg; $x }xmsge; print $str; } " file='path/goes/here' foo'a/b/c'bar '///' 'a/b/c' file1='aa/bb/cc',file2='/dd/' file='path/goes/here' file='xxxx/xxxx/xxxx' foo'a/b/c'bar foo'x/x/x'bar '///' '///' 'a/b/c' 'x/x/x' file1='aa/bb/cc',file2='/dd/' file1='xx/xx/xx',file2='/xx/'
Re: Selectively replacing characters inside a string
by dsheroh (Monsignor) on Jun 11, 2009 at 09:57 UTC
    If I'm reading correctly that you want to replace all non-slash characters with the letter x, the easiest way would seem to be to use tr rather than a regex:
    $ perl -e '$foo = "/some/path/to/a/file"; $foo =~ tr|/|x|c; print "$fo +o\n";' /xxxx/xxxx/xx/x/xxxx
      I do want to replace all non-slash characters with the letter x, but only on a portion of the input string. Specifically, the part between the quotes in file="some/path". And actually, I didn't make it clear, but there will be text before and after the file="some/path", so I have to be careful about what I substitute. The actual input line would look more like:
      2009-06-10 19:37:29 GMT [more text here] file="some/path" status=0 des +tination="some more text"
      And the only thing I want to filter is the path inside of the file="some/path" stuff.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://770487]
Approved by GrandFather
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (3)
As of 2024-09-10 01:05 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?
    erzuuli‥ 🛈The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.