use strict; use warnings; use utf8; use feature qw/unicode_strings say/; my $doc = do{ local $/ = undef; ; }; say GetEmailLink($doc) // 'Unable to parse document.'; sub GetEmailLink { my $document = shift; my %component = fetch_obscured_email($document); return unless keys %component; # Detect and pass along failure to parse. my $link = q(); for( my $i = 0; $i != @{$component{cypher}}; ++$i ) { my $linkChar = $component{cypher}[$i] - $component{key}[$i % @{$component{key}}]; $link .= chr($linkChar); } return $link; }; sub fetch_obscured_email { my $data = shift; $data =~ m/ SetEmailLink\s*\(\s* # Function name and opening paren (anchor). [^,]*, # Unwanted first parameter. \s* \[ \s* ( [^]]+ ) \s* \] \s*, # Wanted second parameter. [^,]*, # Unwanted third parameter. \s* \[ \s* ( [^]]+ ) \s* \] \s* # Wanted fourth parameter. \s*\) # Closing paren. /x or return; # Condition: Failure to parse. my( $text_param, $key_param ) = ( $1, $2 ); tr/0-9,//dc for $text_param, $key_param; # Keep only what we need. return( cypher => [ split /,/, $text_param ], key => [ split /,/, $key_param ] ); } __DATA__