in reply to Tell whether two strings differ at only one position

Here's another XOR solution that I think is far more to the point:
sub compare { (($_[0] ^ $_[1]) =~ tr/\0//c) < 2; }
It counts the number of non-NULLs produced by XORing the strings together. If that number is less than 2, then the strings were either identical or differed by only one character. This could also be written as:
sub compare { ($_[0] ^ $_[1]) =~ /^\0*(?:[^\0]\0*)?$/ }
The regex ensures the XORed string is either entirely NULLs or has just one non-NULL in it.

Jeff japhy Pinyan, P.L., P.M., P.O.D, X.S.: Perl, regex, and perl hacker
How can we ever be the sold short or the cheated, we who for every service have long ago been overpaid? ~~ Meister Eckhart

Replies are listed 'Best First'.
Re^2: Tell whether two strings differ at only one position
by rg0now (Chaplain) on Aug 04, 2005 at 19:20 UTC
    Wow! japhy++
    sub compare { (($_[0] ^ $_[1]) =~ tr/\0//c) < 2; }
    While I liked each and every solution other wise monks have been so kind to come up with so far, when I looked at the solution of japhy, I immediately saw that this is the one I have been searching for! It is clean and concise and perlish, and, quite amazingly, it is just one statement, so I can eliminate the compare sub alltogether which, as I hope, will make my script even faster!

    I am beginning to see that after a certain point, Perl programming becomes a matter of pure aesthetics...

      Except it doesn't work:
      sub compare { (($_[0] ^ $_[1]) =~ tr/\0//c) < 2; } print((compare('abc', 'abcd') ? 'ok' : 'not ok'), "\n");
      It should be
      sub compare { length $_[0] == length $_[1] && (($_[0] ^ $_[1]) =~ tr/\0//c) < 2; }
        Thanks ikegami for pointing this one little important fact out to me! I have almost forgot my very own specifications for the problem. That tr///c absolutely made my day...
Re^2: Tell whether two strings differ at only one position
by blazar (Canon) on Aug 05, 2005 at 09:12 UTC
    This is what I wanted to do myself in the first place. Only that... I plainly didn't remember about the /c switch! And I tried with the /d one (without assignment, that is) but it failed like this:
    Can't modify bitwise xor (^) in transliteration (tr///) at foo.pl line + 7, near "tr/\0//d) "
    So I adopted a temp variable. Incidentally I wonder why I don't get the same error if I omit /d (with or without /c)... in both cases I'm attempting at modifying it, am I not?

      With /d and /c, you are modifying the string.

      Without either, and with source & destination tables being the same, is a special case designed for counting only.

      There would be no point in modifying the string just to replace like with like.


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
      "Science is about questioning the status quo. Questioning authority".
      The "good enough" maybe good enough for the now, and perfection maybe unobtainable, but that should not preclude us from striving for perfection, when time, circumstance or desire allow.