#! /usr/bin/perl -l # John rules generator for combination of 1337-speak substitutions. # Proof of concept # Copyright © 2014 Aleksey Cherepanov # Redistribution and use in source and binary forms, with or without # modification, are permitted. use strict; use warnings; use Data::Dumper; # TODO: Do we need to replace letter with itself? I guess, no. my %replacements = qw/s [S5$] e [E3]/; # Each letter could be replaced in $max_count places my $max_count = 2; # Try positions up to $max_pos position my $max_pos = 5; my @letters = keys %replacements; my @letters_counts = (0) x @letters; sub generate_positions { my $c = shift; return [] if $c == 0; my $mp = shift; my @r; for my $p ($c .. $mp) { my @t = generate_positions($c - 1, $p - 1); push @$_, $p for @t; push @r, @t; } @r } # warn Dumper [generate_positions 2, 4]; # TODO: We don't replace all. Do that separately. sub combine { my $a = shift; my $b = shift; # warn Dumper $a, $b; my @r; # return @$a unless @$b; for my $i (@$a) { for my $j (@$b) { push @r, [@$i, $j]; } } @r } while (1) { # Print variants for given counts my @rules = []; # warn Dumper [@letters_counts]; for (0 .. $#letters) { my $letter = $letters[$_]; my $replacement = $replacements{$letter}; my $count = $letters_counts[$_]; my @letter_rules; if ($count > 0) { my @positions = generate_positions($count, $max_pos); # warn Dumper [$count, $max_pos, @positions]; for (@positions) { # We use positions in back order so first replacement # does not change numbers of others. # TODO: We may exploit change and simplify rules: # %2s op[S5$] %1s op[S5$] -> %1s op[S5$] %1s op[S5$] push @letter_rules, join " ", map { "%$_$letter op$replacement" } reverse @$_; } @rules = combine [@rules], [@letter_rules]; } } # warn Dumper [@rules]; for (@rules) { if ($#$_ == -1) { print ":" } else { print join " ", @$_; } } # Increase counts like: 0,0,0 -> 0,0,1 -> 0,0,2 -> 0,1,0 $letters_counts[$#letters_counts]++; my $i = $#letters_counts; for (; $i > 0 && $letters_counts[$i] > $max_count; $i--) { $letters_counts[$i] = 0; $letters_counts[$i - 1]++; } last if $i == 0 && $letters_counts[$i] > $max_count; }