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

I have this code:
$file = "path/to/file"; open( FILE, "<", "$file") or die $!\n"; $_ = do { local $/; <FILE> }; close(FILE); $not_filtered = $_; s/match/replace/gi; s/match1/replace1/gi; print $_;
How do I print only differences, between initial value ($not_filtered) and final value of $_? I found String::Diff, but I don't want to load an extra module. Thank you!!

Replies are listed 'Best First'.
Re: Comparing $_ --- before/after
by ssandv (Hermit) on Oct 10, 2009 at 15:05 UTC

    So, this is going to be the part where people are going to start getting snarky. You've waved your hands and said "I want the differences" without explaining what you mean, you gave exactly one toy example which is hardly sufficient to specify anything, and you've given weak reasons for not wanting to include a module or steal the code from one, and no actual reason not to use a shell function other than "it wouldn't be pure Perl". (Don't you think the code in a module is likely to be reasonably compact and solid? Why do you expect to get something better here?)

    If you want a decent answer, you'll have to explain yourself thoroughly. (And tell us what the full problem you're attempting to solve is, this sounds like an XY problem. Or homework.) Your criteria sound increasingly absurd without a better explanation. Is your next complaint going to be that you want a one-liner?

    Define and explain the expected result for the following, and we might get *somewhere*:

    "Banana" / "banana" "banana" / "Banana" "Bananananafofana" / "Bafana" "Bafana" / "Bananananafofana" "Banana" / "anaBanana" "anaBanana" / "Banana" "Banana" / "Bazaza" "Banana" / "Bannana" "Bannana" / "Banana"

    Or else, do what I said up above, and do the printing immediately after the substitution when you know what you've swapped out. (Hint: the different letters are probably whatever's in the right hand side of the s/// if the substitution works, at least for your example where it's a simple string.)

      Update
      for not wanting to include a module or steal the code from one, and no actual reason not to use a shell function other than "it wouldn't be pure Perl".
      I'm still learning man and I want to learn perl not shell. I already tried to "steal" the code but you have no idea how many subroutines involves that module. I'm not so advanced to "steal" that code. I just want to find out a simpler way for:
      string2 - string1 = difference
      It's not necessary to become rude. I thought this is a place where perl gurus can share their experience with newbs like me. But nevermind.

        That doesn't even make sense. There's not a uniform meaning of string subtraction. If you'd answer my sample problems above, it would help. There's *not* a unique way. You have to decide and tell us if you want us to help you. You tell us by giving lots of good examples, not one bad one. This isn't a Perl problem, it's a failure to clearly specify intended results problem, which is language independent.

        Further, the gurus *did* share information with you, and you rejected all of it.

        It would be helpful if you could give say 5-6 examples of what you want, meaning input strings and desired output.

        The general problem of how to compare text and determine "how close" one string is to another is very complex.

        I'm not quite sure, but I think you just need some code that points out where the 2 strings diverge (first char that doesn't match). The simple code below is a step in that direction. I'm sure you will need to modify this to your needs, but I hope this gets you started on the "path".

        #!usr/bin/perl -w use strict; my $string1 = "abcdf"; my $string2 = "abcde"; #for this simple comparision, I assume that using #the longest string as the iterator value #which will be "string1", is "better". if ( length($string2) > length ($string1) ) { ($string1,$string2) = ($string2,$string1); #in Perl an intermediate "temp" is not necessary } my @string2 = split (//,$string2); #array of characters my $result=""; foreach (split (//,$string1)) #loop var is $_ over chars in #string1 { my $char = shift (@string2); if (defined ($char) && $char eq $_ ) { $result .= "1"; } else { $result .= $_; } } print "CharbyCharResult =$result\n"; print "difference is:",grep{!/1/}split(//,$result),"\n"; __END__ EXAMPLE RUNS: my $string1 = "abcdf"; my $string2 = "abcde"; CharbyCharResult =1111f difference is:f my $string1 = "abcdfccc"; my $string2 = "abcde"; CharbyCharResult =1111fccc difference is:fccc my $string1 = "abcdf"; my $string2 = "abcdeeeee"; CharbyCharResult =1111eeeee difference is:eeeee my $string1 = "abcdfxy"; my $string2 = "abcdexzy"; CharbyCharResult =1111e1zy difference is:ezy
Re: Comparing $_ --- before/after
by ssandv (Hermit) on Oct 10, 2009 at 08:47 UTC

    Instead of slurping the file into a scalar, read it to an array, and then do the substitutions one line at a time, printing as you go if you succeed at substituting on the line. I'm loath to attempt to code it since I should have been in bed quite a while ago, but in general if you want line-by-line action and control on a file, you shouldn't put it in a scalar.

      Ok, let's simplify this.
      $string1 = "abcdf"; $string2 = "abcde"; #how to display difference between $string2 and $string1? $difference = "f";

        I'm not sure what do you call "difference". Can you give more strict definition? What is the difference between "Lazy dog" and "Loony owl"?

Re: Comparing $_ --- before/after
by lamprecht (Friar) on Oct 10, 2009 at 10:12 UTC
    Hi,

    you could use the diff command:

    use strict; use warnings; my $file = "file"; open( FILE, "<", $file) or die "$!\n"; $_ = do { local $/; <FILE> }; close(FILE); s/match/replace/gi; s/match1/replace1/gi; open(my $new_file,'>','new_file')or die "$!\n"; print $new_file $_; close $new_file or die "$!\n"; print `diff $file new_file`;

    Cheers, Christoph
      Yes, but it's no longer pure perl and diff working only for files.
Re: Comparing $_ --- before/after
by AnomalousMonk (Archbishop) on Oct 10, 2009 at 09:55 UTC
    Even if you really do have a good reason for not wanting to download and use what looks, at first glance, like a fairly short and simple pure-Perl module (String::Diff), why not just steal the code (with appropriate credit given, of course)?

    Update: Oops... Just noticed that String::Diff is dependent on Algorithm::Diff, so maybe it's a little more involved than I first thought. Still, there's a lot of good code available...

      The reason for not doing this, I want a simpler way instead of loading extra code from a module + installing some dependencies.
        Using a module is much simpler than writing and testing (don't forget to test it!) your own code which duplicates any but the most trivial functionality - and this particular problem is not exceptionally trivial. (It's not even well-defined yet... As an earlier response asked, what do you consider to be the difference between "Lazy Dog" and "Looney Owl"?)

        I'm not saying re-inventing wheels is bad - I do it all the time - but it does not make things simpler.

        Well, there's still a lot of code out there. Try a Super Search on  'string' and  'difference' (and similar terms) to get started with a lot of good leads.