To steph_bow: My solution is written below for reference.

#! /usr/bin/perl use strict; while (my $line = <DATA>) { chomp $line; my @line = split ";", $line; next if $line[0] eq $line[1]; next unless length $line[0] == length $line[1]; my @one = breakup($line[0]); my @two = breakup($line[1]); next unless scalar(@one) == scalar(@two); my @match = map { $one[$_] eq ++$two[$_] || ++$one[$_] eq --$two[$_] ? 1 : 0 } (0..$#one); print $line, "\n" if 1 == grep {$_} @match; } sub breakup { my @out; while ($_[0]) { $_[0] =~ s/^([a-zA-z]|[0-9]+)//; push @out, $1; } return @out; }
[download]

To answer your first question, the while ($_[0]) checks the first argument of breakup each time before it loops again. Note how the s/// regex is finding either a group of letters or a group of numbers at the beginning of the string in question and replacing it with nothing. This group is then pushed onto @out. This means that the inputted string stored in $_[0] is getting smaller, and when it's completely gone the while loop will stop.

Your second question refers to the part of my solution that checks if the each element of the broken-up strings either match or are only different by one unit. The incremental operators ++ and -- work both on strings and numbers. $one[$_] eq ++$two[$_] checks to see if $two is one unit less than $one. However, at the same time, it permanently increases $two by one unit. Therefore, in order to check if $two is one unit more than $one, we have to decrement it, as in ++$one[$_] eq --$two[$_]. Try it with some test numbers and it will be easier to understand.