feat(воронка): ключ сравнения ниш — регистр, ё, латинские двойники
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Support;
|
||||
|
||||
/**
|
||||
* Ключ сравнения ниш. Нужен, чтобы «Окна», «окна», «Окна » и «Окнa» с латинской
|
||||
* буквой считались одной и той же нишей и не расползались по доске дублями.
|
||||
*
|
||||
* Ключ — только для СРАВНЕНИЯ. Хранится и показывается всегда живое написание.
|
||||
*/
|
||||
final class RubricKey
|
||||
{
|
||||
/**
|
||||
* Латинские буквы, неотличимые на глаз от кириллических. Подменяются ТОЛЬКО в
|
||||
* строке, где есть хоть одна кириллическая буква: иначе честная ниша «SPA»
|
||||
* превратилась бы в «sра» и склеилась бы с чем попало.
|
||||
*/
|
||||
private const LOOKALIKES = [
|
||||
'a' => 'а', 'c' => 'с', 'e' => 'е', 'o' => 'о', 'p' => 'р', 'x' => 'х',
|
||||
'y' => 'у', 'k' => 'к', 'm' => 'м', 'h' => 'н', 't' => 'т', 'b' => 'в',
|
||||
];
|
||||
|
||||
public static function make(?string $raw): string
|
||||
{
|
||||
$s = mb_strtolower(trim((string) $raw), 'UTF-8');
|
||||
|
||||
if (preg_match('/\p{Cyrillic}/u', $s) === 1) {
|
||||
$s = strtr($s, self::LOOKALIKES);
|
||||
}
|
||||
|
||||
$s = str_replace('ё', 'е', $s);
|
||||
$s = (string) preg_replace('/[^\p{L}\p{N}]+/u', ' ', $s);
|
||||
|
||||
return trim((string) preg_replace('/\s+/u', ' ', $s));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Support\RubricKey;
|
||||
|
||||
test('регистр, лишние пробелы и пунктуация ключ не меняют', function () {
|
||||
expect(RubricKey::make('Окна'))->toBe(RubricKey::make(' окна '))
|
||||
->and(RubricKey::make('Окна'))->toBe(RubricKey::make('«Окна».'))
|
||||
->and(RubricKey::make('Ремонт, стройка'))->toBe(RubricKey::make('ремонт стройка'));
|
||||
});
|
||||
|
||||
test('ё и е — одна буква', function () {
|
||||
expect(RubricKey::make('Клёны'))->toBe(RubricKey::make('Клены'));
|
||||
});
|
||||
|
||||
test('латинские двойники в русском слове приводятся к кириллице', function () {
|
||||
// «Окнa» — последняя буква латинская.
|
||||
expect(RubricKey::make("Окн\u{0061}"))->toBe(RubricKey::make('Окна'));
|
||||
});
|
||||
|
||||
test('чисто латинское название не калечится', function () {
|
||||
expect(RubricKey::make('SPA'))->toBe('spa')
|
||||
->and(RubricKey::make('IT'))->toBe('it');
|
||||
});
|
||||
|
||||
test('пустая строка даёт пустой ключ', function () {
|
||||
expect(RubricKey::make(null))->toBe('')
|
||||
->and(RubricKey::make(' '))->toBe('');
|
||||
});
|
||||
Reference in New Issue
Block a user