Completed
Push — master ( 6a4e7a...d894f8 )
by Magnar Ovedal
04:34
created

Leetspeak   A

Complexity

Total Complexity 13

Size/Duplication

Total Lines 85
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
eloc 42
dl 0
loc 85
ccs 24
cts 24
cp 1
rs 10
c 0
b 0
f 0
wmc 13

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 3
A getDecodeMap() 0 11 3
A formatWord() 0 11 5
A apply() 0 4 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Stadly\PasswordPolice\WordFormatter;
6
7
use Stadly\PasswordPolice\WordFormatter;
8
use Traversable;
9
10
final class Leetspeak implements WordFormatter
11
{
12
    /**
13
     * @var array<string, string[]>
14
     */
15
    private $encodeMap = [
16
        'A' => ['4', '@', '∂'],
17
        'B' => ['8', 'ß'],
18
        'C' => ['(', '¢', '<', '[', '©'],
19
        'D' => ['∂'],
20
        'E' => ['3', '€', 'є'],
21
        'F' => ['ƒ'],
22
        'G' => ['6', '9'],
23
        'H' => ['#'],
24
        'I' => ['1', '!', '|', ':'],
25
        'J' => ['¿'],
26
        'K' => ['X'],
27
        'L' => ['1', '£', 'ℓ'],
28
        'O' => ['0', '°'],
29
        'R' => ['2', '®', 'Я'],
30
        'S' => ['5', '$', '§'],
31
        'T' => ['7', '†'],
32
        'U' => ['µ'],
33
        'W' => ['vv'],
34
        'X' => ['×'],
35
        'Y' => ['φ', '¥'],
36
        'Z' => ['2', '≥'],
37
    ];
38
39
    /**
40
     * @var array<string|int, string[]>
41
     */
42
    private $decodeMap = [];
43
44 1
    public function __construct()
45
    {
46 1
        foreach ($this->encodeMap as $char => $encodedChars) {
47 1
            foreach ($encodedChars as $encodedChar) {
48 1
                $this->decodeMap[$encodedChar][] = $char;
49
            }
50
        }
51 1
    }
52
53
    /**
54
     * @param string $word Word to get decode map for.
55
     * @return array<string|int, string[]> Map for decoding the word prefix.
56
     */
57 4
    private function getDecodeMap(string $word): array
58
    {
59 4
        $decodeMap = [];
60 4
        foreach ($this->decodeMap as $encodedChar => $chars) {
61 4
            if ((string)$encodedChar === mb_substr($word, 0, mb_strlen((string)$encodedChar))) {
62 4
                $decodeMap[$encodedChar] = $chars;
63
            }
64
        }
65 4
        $decodeMap[mb_substr($word, 0, 1)][] = mb_substr($word, 0, 1);
66
67 4
        return $decodeMap;
68
    }
69
70
    /**
71
     * {@inheritDoc}
72
     */
73 4
    public function apply(iterable $words): Traversable
74
    {
75 4
        foreach ($words as $word) {
76 4
            yield from $this->formatWord($word);
77
        }
78 4
    }
79
80
    /**
81
     * @param string $word Word to format.
82
     * @return Traversable<string> Formatted words. May contain duplicates.
83
     */
84 4
    private function formatWord(string $word): Traversable
85
    {
86 4
        if ($word === '') {
87 4
            yield '';
88 4
            return;
89
        }
90
91 4
        foreach ($this->getDecodeMap($word) as $encodedChar => $chars) {
92 4
            foreach ($this->formatWord(mb_substr($word, mb_strlen((string)$encodedChar))) as $suffix) {
93 4
                foreach ($chars as $char) {
94 4
                    yield $char.$suffix;
95
                }
96
            }
97
        }
98 4
    }
99
}
100