4

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

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

我只想知道一个字符是否是一个键,两个键或两个以上键距另一个字符。

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

4

5 回答 5

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

公式为:

  • 字符是c1​​ 和c2
  • 查找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
于 2011-10-01T15:23:41.753 回答
3

在理想化的键盘上构建从键到位置的映射。就像是:

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

然后您可以将“距离”作为两点之间的数学距离。

于 2011-10-01T15:20:42.623 回答
3

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

+---+---+---+---+---+---+---
|   | 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 为正或负,以显示第二个字母从第一个字母向上或向下。快打电话给我的专利代理人!

于 2011-10-01T15:28:59.450 回答
1

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

例如,考虑键盘的左侧:

  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所以和之间的距离bsqrt((4 - 0)^2 + (3 - 2)^2)

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

于 2011-10-01T15:25:32.813 回答
0

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

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

于 2021-06-30T08:51:23.890 回答