Как я могу определить, близок ли символ к другому символу на клавиатуре QWERTY?

Я разрабатываю систему обнаружения спама, и меня предупредили, что она не может обнаружить такие строки — «asdfsdf».

Мое решение этой проблемы включает определение того, были ли предыдущие клавиши рядом с другими клавишами на клавиатуре. Я не получаю ввод (для обнаружения спама) с клавиатуры, я получаю его в виде строки.

Все, что я хочу знать, это то, находится ли персонаж на расстоянии одной клавиши, двух клавиш или более двух клавиш от другого персонажа.

Например, на современной клавиатуре QWERTY символы «q» и «w» будут находиться на расстоянии 1 клавиши. То же самое будет с символами «q» и «s». Люди могут понять это логически, как я могу сделать это в коде?


person liamzebedee    schedule 01.10.2011    source источник
comment
На каком языке вы разрабатываете?   -  person garnertb    schedule 01.10.2011
comment
Извините, я не отметил это, это PHP. Просто отмечаю сейчас...   -  person liamzebedee    schedule 01.10.2011
comment
Какова целевая группа пользователей? Не все клавиатуры QWERTY, например, в Германии распространена раскладка QWERTZ. en.wikipedia.org/wiki/QWERTZ.   -  person ivarni    schedule 01.10.2011
comment
Это в основном для моих собственных целей, небольшой проект, который я начал всего 1 час назад, однако он довольно быстро растет. Поэтому я не собираюсь поддерживать другие макеты, пока не буду готов   -  person liamzebedee    schedule 01.10.2011
comment
Тогда я бы не стал сейчас делать предположения о клиентской клавиатуре, но имейте в виду, что не все клавиатуры имеют одинаковую раскладку, поэтому, если вы столкнетесь с проблемами из-за этого, вам, вероятно, придется выяснить языковой стандарт пользователя и применить другое сопоставление ключей на его основе.   -  person ivarni    schedule 01.10.2011


Ответы (5)


Вы можете просто создать двухмерную карту для стандартной клавиатуры qwerty. В основном это может выглядеть примерно так:

map[0][0] = 'q';
map[0][1] = 'a';
map[1][0] = 'w';
map[1][1] = 's';

и так далее.

Когда вы получаете два символа, вам просто нужно найти их x и y в массиве «карта» выше, и вы можете просто вычислить расстояние, используя Пифагор. Это не удовлетворит требованиям, которые у вас были, поскольку «q» и «s» находятся на расстоянии 1. Но скорее это будет sqrt(1^2 + 1^2) приблизительно 1,4

Формула будет:

  • Символы c1 и c2
  • Найдите координаты для c1 и c2: (x1,y1) и (x2,y2)
  • Вычислите расстояние с помощью Пифагора: dist = sqrt((x2-x1)^2 + (y2-y1)^2).
  • При необходимости потолките или перекройте результат.

Например:

Допустим, вы получаете символы c1='q' и c2='w'. Изучите карту и найдите, что 'q' имеет координаты (x1,y1) = (0, 0), а 'w' имеет координаты (x2,y2) = (1, 0). Расстояние

sqrt((1-0)^2 + (0-0)^2) = sqrt(1) = 1
person Alexander Olsson    schedule 01.10.2011
comment
Великолепно! Это точное решение, с уравнением и всем остальным, я бы никогда не подумал об этом. - person liamzebedee; 01.10.2011
comment
Рад помочь. Не забудьте принять ответ, если он полностью ответил на ваш вопрос. - person Alexander Olsson; 01.10.2011

Создайте карту от клавиш до позиций на идеализированной клавиатуре. Что-то вроде:

'q' => {0,0},
'w' => {0,1},
'a' => {1,0},
's' => {1,1}, ...

Затем вы можете взять «расстояние» как математическое расстояние между двумя точками.

person Mat    schedule 01.10.2011
comment
Вам понадобится отдельная карта для каждой общей раскладки клавиатуры. Французский спам будет исходить, например, с клавиатуры AZERTY. - person rossum; 01.10.2011

Что ж, посмотрим. Это тяжело. Я всегда использую метод грубой силы и держусь подальше от сложных концепций, подобных тому, что пытался нам навязать Пифагор, так как насчет двумерной таблицы? Что-то вроде этого. может быть:

+---+---+---+---+---+---+---
|   | a | b | c | d | f | s ...
+---+---+---+---+---+---+---
| a | 0 | 5 | 4 | 2 | 4 | 1 ...
| b | 5 | 0 | 3 | 3 | 2 | 4 ...
| c | 4 | 3 | 0 | 1 | 2 | 2 ...
| d | 2 | 3 | 1 | 0 | 1 | 1 ...
| f | 3 | 2 | 2 | 1 | 0 | 2 ...
| s | 1 | 4 | 2 | 1 | 2 | 0 ...
+---+---+---+---+---+---+---

Это может сработать для тебя? У вас могут быть даже отрицательные числа, чтобы показать, что одна клавиша находится слева от другой. ПЛЮС вы можете поместить 2-целочисленную структуру в каждую ячейку, где второе целое число положительное или отрицательное, чтобы показать, что вторая буква выше или ниже первой. Позвони моему патентному поверенному, быстро!

person Pete Wilson    schedule 01.10.2011
comment
Интересное решение, не совсем то, что я хотел, но другой подход.. Мне нравится - person liamzebedee; 01.10.2011

Основная идея состоит в том, чтобы создать карту символов и их положения на клавиатуре. Затем вы можете использовать простую формулу расстояния, чтобы определить, насколько близко они друг к другу.

Например, рассмотрим левую часть клавиатуры:

  1 2 3 4 5 6
  q w e r t
  a s d f g
  z x c v b

Персонаж a имеет позицию [2, 0], а персонаж b имеет позицию [3, 4]. Формула для их расстояния друг от друга:

sqrt((x2-x1)^2 + (y2-y1)^2);

Таким образом, расстояние между a и b равно sqrt((4 - 0)^2 + (3 - 2)^2).

Вам потребуется немного усилий, чтобы сопоставить ключи с прямоугольной сеткой (мой пример не идеален, но дает представление). Но после этого вы можете построить карту (или словарь), а поиск будет простым и быстрым.

person Jim Mischel    schedule 01.10.2011

Я разработал функцию для той же цели в PHP, потому что хотел посмотреть, смогу ли я использовать ее для анализа строк, чтобы выяснить, могут ли они быть спамом.

Это для клавиатуры QWERTZ, но ее можно легко изменить. Первое число в массиве $keys — это приблизительное расстояние слева, а второе — номер строки сверху.

function string_distance($string){
    $keys=array(
        'q'=>array(1,1),
        'w'=>array(2,1),
        'e'=>array(3,1),
        'r'=>array(4,1),
        't'=>array(5,1),
        'z'=>array(6,1),
        'u'=>array(7,1),
        'i'=>array(8,1),
        'o'=>array(9,1),
        'p'=>array(10,1),
        'a'=>array(1.25,2),
        's'=>array(2.25,2),
        'd'=>array(3.25,2),
        'f'=>array(4.25,2),
        'g'=>array(5.25,2),
        'h'=>array(6.25,2),
        'j'=>array(7.25,2),
        'k'=>array(8.25,2),
        'l'=>array(9.25,2),
        'y'=>array(1.85,3),
        'x'=>array(2.85,3),
        'c'=>array(3.85,3),
        'v'=>array(4.85,3),
        'b'=>array(5.85,3),
        'n'=>array(6.85,3),
        'm'=>array(7.85,3)
    );
    $string=preg_replace("/[^a-z]+/",'',mb_strtolower($string));
    for($i=0;$i+1<mb_strlen($string);$i++){
        $char_a=mb_substr($string,$i,1);
        $char_b=mb_substr($string,$i+1,1);
        $a=abs($keys[$char_a][0]-$keys[$char_b][0]);
        $b=abs($keys[$char_a][1]-$keys[$char_b][1]);
        $distance=sqrt($a^2+$b^2);
        $distances[]=$distance;
    }
    return array_sum($distances)/count($distances);
}

Вы можете использовать его следующим образом.

string_distance('Boat') # output 2.0332570942187
string_distance('HDxtaBQrGkjny') # output 1.4580596252044

Я использовал многобайтовые функции, потому что думал о расширении их для других символов. Можно расширить его, проверив регистр символов.

person B. Martin    schedule 30.06.2021