Completed
Push — master ( 40399a...d60c0b )
by Magnar Ovedal
09:46 queued 06:05
created

LeetDecoder::applyCurrent()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

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