In search of elegant code - do two strings differ by one character?

U

usenet

I wish to construct a subroutine which will accept two strings and
return True if they differ by ONLY one "extra" character
(case-sensitive). For example, it would return true if passed qw/Perl
Pearl/, but false for qw/Perl Preal/. It would be nice if it could also
identify single-character variances (without an additional character,
ie, qw/Perl Pell/ or qw/Perl perl/)

I suspect there's a module that will save me the bother of writing an
ugly, brute-force, one-character-at-a-time parser/comparitor. I had a
look at Text::Diff but it doesn't seem to fill this particular need
(and, of course, it's not designed to). And I looked at a few others as
well, but no luck (I couldn't even figure out what Text::Compare is
supposed to do!).

I can write the ugly code (I'm pretty good at that!), but I'd
appreciate anyone who can refer me to something better.
 
J

John W. Krahn

I wish to construct a subroutine which will accept two strings and
return True if they differ by ONLY one "extra" character
(case-sensitive). For example, it would return true if passed qw/Perl
Pearl/, but false for qw/Perl Preal/. It would be nice if it could also
identify single-character variances (without an additional character,
ie, qw/Perl Pell/ or qw/Perl perl/)

I suspect there's a module that will save me the bother of writing an
ugly, brute-force, one-character-at-a-time parser/comparitor. I had a
look at Text::Diff but it doesn't seem to fill this particular need
(and, of course, it's not designed to). And I looked at a few others as
well, but no luck (I couldn't even figure out what Text::Compare is
supposed to do!).

I can write the ugly code (I'm pretty good at that!), but I'd
appreciate anyone who can refer me to something better.

It looks like you might need a Levenshtein Distance algorithm or
something similar.

Here is a Perl version of one:

sub levenshtein {
my ( $A, $B ) = @_;
my ( $len_A, $len_B ) = ( length $A, length $B );
return $len_B unless $len_A;
return $len_A unless $len_B;

my @W = 0 .. $len_B;
my $next;
for my $i ( 0 .. $len_A - 1 ) {
my $cur = $i + 1;
for my $j ( 0 .. $len_B - 1 ) {
my ( $x, $y, $z ) =
( $W[ $j + 1 ] + 1,
$cur + 1,
$W[ $j ] + ( substr($A,$i,1) ne substr($B,$j,1) )
);
$W[ $j ] = $cur;
$cur = $next = $x < $y && $x < $z ? $x : $y < $z ? $y : $z;
}
$W[ $len_B ] = $next;
}
return $next;
}



John
 
A

Anno Siegel

I wish to construct a subroutine which will accept two strings and
return True if they differ by ONLY one "extra" character
(case-sensitive). For example, it would return true if passed qw/Perl
Pearl/, but false for qw/Perl Preal/. It would be nice if it could also
identify single-character variances (without an additional character,
ie, qw/Perl Pell/ or qw/Perl perl/)

I suspect there's a module that will save me the bother of writing an
ugly, brute-force, one-character-at-a-time parser/comparitor. I had a
look at Text::Diff but it doesn't seem to fill this particular need
(and, of course, it's not designed to). And I looked at a few others as
well, but no luck (I couldn't even figure out what Text::Compare is
supposed to do!).

Search CPAN for "approx", it should come up with something.
I can write the ugly code (I'm pretty good at that!), but I'd
appreciate anyone who can refer me to something better.

sub one_extra {
my ( $short, $long) = @_;
return 0 unless 1 + length $short == length $long;
grep $_ eq $short, map { substr( my $t = $long, $_, 1, ''); $t}
0 .. length $short;
}

Anno
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top