【问题标题】:How could I detect if a character close to another character on a QWERTY keyboard?如何检测 QWERTY 键盘上的字符是否接近另一个字符?
【发布时间】:2011-11-29 01:55:27
【问题描述】:

我正在开发一个垃圾邮件检测系统,但我发现它无法检测到这样的字符串 - “asdfsdf”。

我对此的解决方案包括检测之前的键是否靠近键盘上的其他键。我没有从键盘获取输入(用于检测垃圾邮件),而是以字符串的形式获取。

我只想知道一个字符距离另一个字符是一个键、两个键还是两个以上键。

例如,在现代 QWERTY 键盘上,字符“q”和“w”将相距 1 个键。字符“q”和“s”也是如此。人类可以从逻辑上解决这个问题,我怎么能在代码中做到这一点?

【问题讨论】:

  • 你用什么语言开发?
  • 对不起,我没有标记它,它的 PHP。现在只是标记...
  • 目标用户群是什么?并非所有键盘都是 QWERTY,例如德国的常见布局有 QWERTZ。 en.wikipedia.org/wiki/QWERTZ.
  • 它主要是出于我自己的目的,一个小项目,我才1小时前开始,但是它的增长很快。所以在我准备好之前我不会支持其他布局
  • 那么我现在不用担心对客户端键盘做出假设,但请记住,并非所有键盘都具有相同的布局,因此如果您在路上遇到问题您可能需要弄清楚用户的语言环境并基于此应用不同的键映射。

标签: php string keyboard spam-prevention qwerty


【解决方案1】:

我在 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

我使用多字节函数是因为我正在考虑将它扩展到其他字符。也可以通过检查字符的大小写来扩展它。

【讨论】:

    【解决方案2】:

    好吧,让我们看看。这是一个艰难的。我总是采用蛮力方法,我远离毕达哥拉斯试图强加给我们的高级概念,那么二维表怎么样?像这样的东西。也许:

    +---+---+---+---+---+---+---
    |   | 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 整数结构,其中第二个 int 为正或负,以显示第二个字母从第一个字母向上或向下。快打电话给我的专利律师!

    【讨论】:

    • 有趣的解决方案,不是我想要的,而是另一种方法..我喜欢它
    【解决方案3】:

    基本思想是创建一个字符映射及其在键盘上的位置。然后,您可以使用简单的距离公式来确定它们之间的距离。

    例如,考虑键盘的左侧:

      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);
    

    所以ab之间的距离是sqrt((4 - 0)^2 + (3 - 2)^2)

    将键映射到矩形网格中需要花费一些精力(我的示例并不完美,但它为您提供了思路)。但是之后你可以建立一个地图(或字典),查找简单快捷。

    【讨论】:

      【解决方案4】:

      您可以简单地为标准 qwerty 键盘创建一个二维映射。 基本上它可能看起来像这样:

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

      等等。

      当你得到两个字符时,你只需要在上面的数组'map'中找到它们的x和y,并且可以使用pythagoras简单地计算距离。它不能满足您的要求,因为 'q' 和 's' 距离为 1。但它会是 sqrt(1^2 + 1^2) 大约 1.4

      公式是:

      • 字符为 c1c2
      • 查找 c1c2 的坐标:(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
      

      【讨论】:

      • 太棒了!这是确切的解决方案,有方程和一切,我从来没有想过这个。
      • 很高兴为您提供帮助。如果它完全回答了您的问题,请不要忘记接受答案。
      【解决方案5】:

      在理想化的键盘上构建从键到位置的映射。比如:

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

      那么你可以把“距离”作为两点之间的数学距离。

      【讨论】:

      • 您需要为每个常见的不同键盘布局使用不同的地图。例如,法语垃圾邮件将来自 AZERTY 键盘。
      猜你喜欢
      • 2012-02-20
      • 2017-02-21
      • 2013-05-12
      • 2010-10-13
      • 2022-03-31
      • 1970-01-01
      • 2020-02-02
      相关资源
      最近更新 更多