TyposGenerator::doubleCharTypos()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 15
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 10
nc 3
nop 2
dl 0
loc 15
rs 9.9332
c 0
b 0
f 0
1
<?php
2
/**
3
 * @author Serhii Nekhaienko <[email protected]>
4
 * @license MIT
5
 * @copyright Serhii Nekhaienko (c) 2019
6
 * @copyright Michel Le Quer (c) 2016
7
 * @version 1.0
8
 */
9
10
namespace SerhiiMe\Typos;
11
12
use SerhiiMe\Typos\Exception\KeyboardNotFoundException;
13
use SerhiiMe\Typos\Exception\KeyNotFoundException;
14
use SerhiiMe\Typos\Exception\StorageNotFoundException;
15
use SerhiiMe\Typos\Exception\WrongKeyboardException;
16
use SerhiiMe\Typos\Exception\WrongStorageException;
17
use SerhiiMe\Typos\Keyboard\EnglishKeyboard;
18
use SerhiiMe\Typos\Keyboard\IKeyboard;
19
use SerhiiMe\Typos\Storage\ITyposStorage;
20
use SerhiiMe\Typos\Storage\ArrayTyposStorage;
21
22
/**
23
 * Based on https://packagist.org/packages/mlequer/typos-generator
24
 * Class TyposGenerator
25
 * @package SerhiiMe\Typos
26
 */
27
class TyposGenerator
28
{
29
    /**
30
     * @var string Classname of Storage class
31
     */
32
    private $storage;
33
34
    private $options = [
35
        'wrongKeys' => false,
36
        'missedChars' => false,
37
        'transposedChars' => false,
38
        'doubleChars' => false,
39
        'storage' => ArrayTyposStorage::class,
40
        'keyboard' => EnglishKeyboard::class
41
    ];
42
43
    /**
44
     * @var IKeyboard
45
     */
46
    protected $keyboard;
47
48
    /**
49
     * Constructor.
50
     *
51
     * Options example (options set to false can be ommited):<br/>
52
     * <code>
53
     * $options = [<br/>
54
     *     'wrongKeys' => true,<br/>
55
     *     'missedChars' => true,<br/>
56
     *     'transposedChars' => false,<br/>
57
     *     'doubleChars' => false<br/>
58
     *     'storage' => ArrayTyposStorage::class<br/>
59
     *     'keyboard' => EnglishKeyboard::class
60
     * ];
61
     *
62
     * @param array $options the options to use for the typo generation
63
     * @throws KeyboardNotFoundException
64
     * @throws StorageNotFoundException
65
     * @throws WrongStorageException
66
     * @throws WrongKeyboardException
67
     */
68
    public function __construct(array $options)
69
    {
70
        $this->options = array_merge($this->options, $options);
71
        if (!class_exists($this->options['keyboard'])) {
72
            throw new KeyboardNotFoundException($this->options['keyboard']);
73
        }
74
        if (!class_exists($this->options['storage'])) {
75
            throw new StorageNotFoundException($this->options['keyboard']);
76
        }
77
        if (!in_array(IKeyboard::class, class_implements($this->options['keyboard']))) {
78
            throw new WrongKeyboardException($this->options['keyboard']);
79
        }
80
        if (!in_array(ITyposStorage::class, class_implements($this->options['storage']))) {
81
            throw new WrongStorageException($this->options['storage']);
82
        }
83
84
        $this->setStorage($this->options['storage']);
85
        $this->keyboard = new $this->options['keyboard']();
86
    }
87
88
    /**
89
     * @param string $storage
90
     */
91
    public function setStorage(string $storage)
92
    {
93
        if (in_array(ITyposStorage::class, class_implements($storage, true))) {
94
            $this->storage = $storage;
95
        }
96
    }
97
98
    /**
99
     * @param string $word
100
     * @param ITyposStorage $storage
101
     * @throws KeyNotFoundException
102
     */
103
    protected function wrongKeyTypos(string $word, ITyposStorage &$storage)
104
    {
105
        $typos = [];
106
        $length = mb_strlen($word);
107
108
        for ($i = 0; $i < $length; ++$i) {
109
            $key = $word[$i];
110
            $keys = $this->keyboard->getKey($key);
111
            $tempWord = $word;
112
            foreach ($keys as $char) {
113
                $typos[] = substr_replace($tempWord, $char, $i, 1);
114
            }
115
        }
116
        $storage->addList($typos);
117
    }
118
119
    /**
120
     * @param string $word
121
     * @param ITyposStorage $storage
122
     */
123
    private function missedCharsTypos(string $word, ITyposStorage &$storage)
124
    {
125
        $typos = [];
126
        $length = mb_strlen($word);
127
128
        for ($i = 0; $i < $length; ++$i) {
129
            $tempWord = '';
130
            if ($i == 0) {
131
                $tempWord = substr($word, $i + 1);
132
            } elseif (($i + 1) == $length) {
133
                $tempWord = substr($word, 0, $i);
134
            } else {
135
                $tempWord = substr($word, 0, $i);
136
                $tempWord .= substr($word, $i + 1);
137
            }
138
            $typos[] = $tempWord;
139
        }
140
141
        $storage->addList($typos);
142
    }
143
144
    /**
145
     * @param string $word
146
     * @param ITyposStorage $storage
147
     */
148
    private function transposedCharTypos(string $word, ITyposStorage &$storage)
149
    {
150
        $typos = [];
151
        $length = mb_strlen($word);
152
153
        for ($i = 0; $i < $length; ++$i) {
154
            if (($i + 1) != $length) {
155
                $tempWord = $word;
156
                $tempChar = $tempWord[$i];
157
158
                $tempWord = substr_replace($tempWord, $tempWord[$i + 1], $i, 1);
159
                $tempWord = substr_replace($tempWord, $tempChar, $i + 1, 1);
160
                $typos[] = $tempWord;
161
            }
162
        }
163
164
        $storage->addList($typos);
165
    }
166
167
    /**
168
     * @param string $word
169
     * @param ITyposStorage $storage
170
     */
171
    private function doubleCharTypos(string $word, ITyposStorage &$storage)
172
    {
173
        $typos = [];
174
        $length = mb_strlen($word);
175
176
        for ($i = 0; $i < $length; ++$i) {
177
            $tempWord = substr($word, 0, $i + 1);
178
            $key = $word[$i];
179
            $tempWord .= $key;
180
            if ($i != ($length - 1)) {
181
                $tempWord .= substr($word, $i + 1);
182
            }
183
            $typos[] = $tempWord;
184
        }
185
        $storage->addList($typos);
186
    }
187
188
    /**
189
     * @param $word string | array List of word or one word
190
     * @return array
191
     * @throws KeyNotFoundException
192
     */
193
    public function generate($word): array
194
    {
195
        if (is_string($word)) {
196
            return [$this->getResult($word)];
197
        }
198
        if (is_array($word)) {
199
            $result = [];
200
            foreach ($word as $w) {
201
                $result[] = $this->getResult($w);
202
            }
203
            return $result;
204
        }
205
        return [];
206
    }
207
208
    /**
209
     * @param string $word
210
     * @return ITyposStorage
211
     * @throws KeyNotFoundException
212
     */
213
    protected function getResult(string $word): ITyposStorage
214
    {
215
        $storage = new $this->storage($word);
216
        if ($this->options['wrongKeys']) {
217
            $this->wrongKeyTypos($word, $storage);
218
        }
219
        if ($this->options['missedChars']) {
220
            $this->missedCharsTypos($word, $storage);
221
        }
222
        if ($this->options['transposedChars']) {
223
            $this->transposedCharTypos($word, $storage);
224
        }
225
        if ($this->options['doubleChars']) {
226
            $this->doubleCharTypos($word, $storage);
227
        }
228
229
        return $storage;
230
    }
231
}