3

I have a string (say string 1) that needs to be matched to another string (string2). Both the strings will have the same length and are case in-sensitive.

I want to print the number of character matches between both the strings.

E.g.: String 1: stranger
      String 2: strangem

      Match count = 7

I tried this:

$string1 = "stranger";
$string2 = "strangem";
my $count = $string1 =~ m/string2/ig;

print "$count\n";

How can I fix this?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
I am
  • 1,057
  • 5
  • 14
  • 21

3 Answers3

4

Exclusive or, then count the null characters (where the strings were the same):

my $string1 = "stranger";
my $string2 = "strangem";
my $count = ( lc $string1 ^ lc $string2 ) =~ tr/\0//;

print "$count\n";

I missed the "case in-sensitive" bit.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
ysth
  • 96,171
  • 6
  • 121
  • 214
  • Above code is working fine. Can you please provide what does "^" and tr/\0// represents? – I am Nov 05 '13 at 18:29
  • 1
    `^` is the [exclusive or operator](http://perldoc.perl.org/perlop.html#Bitwise-Or-and-Exclusive-Or), here used in its [string mode](http://perldoc.perl.org/perlop.html#Bitwise-String-Operators). it will produce a string that has \0 wherever the two input strings had the same character. `tr` is the [transliteration operator](http://perldoc.perl.org/perlop.html#tr%2FSEARCHLIST%2FREPLACEMENTLIST%2Fcdsr), here used just to count characters. – ysth Nov 05 '13 at 19:21
  • Don't you need the `c` modifier? eg. `tr/\0//c` – CJ7 Oct 11 '16 at 22:30
  • 1
    @CJ7 that would count non-matches, the question asks for a count of matches – ysth Oct 11 '16 at 23:06
3

You can use substr for that:

#!/usr/bin/perl
use warnings;
use strict;

my $string1=lc('stranger');
my $string2=lc('strangem');
my $count=0;
for (0..length($string1)-1) {
    $count++ if substr($string1,$_,1) eq substr($string2,$_,1);
}
print $count; #prints 7

Or you can use split to get all characters as an array, and loop:

#!/usr/bin/perl
use warnings;
use strict;

my $string1=lc('stranger');
my $string2=lc('strangem');
my $count=0;
my @chars1=split//,$string1; 
my @chars2=split//,$string2;
for (0..$#chars1) {
    $count++ if $chars1[$_] eq $chars2[$_];
}
print $count; #prints 7

(fc gives more accurate results than lc, but I went for backwards compatibility.)

ikegami
  • 367,544
  • 15
  • 269
  • 518
psxls
  • 6,807
  • 6
  • 30
  • 50
0

Not tested

sub cm
{
    my @a = shift;
    my @b = shift;

    # First match prefix of string:
    my $n = 0;
    while ($n < $#a && $n < $#b && $a[$n] eq $b[$n]) {
       ++$n;
    }
    # Then skip one char on either side, and recurse.
    if ($n < $#a && $n < $#b) {
       # Match rest by skipping one place:
       my $n2best = 0;
       my $n2a = cm(splice(@a, $n), splice(@b, $n + 1));
       $n2best = $n2a;
       my $n2b = cm(splice(@a, $n + 1), splice(@b, $n));
       $n2best = $n2b if $n2b > $n2best;
       my $n2c = cm(splice(@a, $n + 1), splice(@b, $n + 1));
       $n2best = $n2c if $n2c > $n2best;
       $n += $n2best;
    }
    return $n;
}

sub count_matches
{
    my $a = shift;
    my $b = shift;

    my @a_chars = split //, $a;
    my @b_chars = split //, $b;
    return cm(@a_chars, @b_chars); 
}

print count_matches('stranger', 'strangem')
Joop Eggen
  • 107,315
  • 7
  • 83
  • 138