QWERTY键盘的助记符密码生成算法

时间:2010-02-05 17:31:31

标签: php algorithm string keyboard qwerty

我有mnemonic”密码生成功能,如下所示:

function Mnemonic($mnemonic)
{
    $result = null;
    $charset = array(str_split('aeiou', 1), str_split('bcdfghjklmnpqrstvwxyz', 1));

    for ($i = 1; $i <= $mnemonic; $i++)
    {
        $result .= $charset[$i % 2][array_rand($charset[$i % 2])];
    }

    return $result;
}

基本上这会生成一个长度为$mnemonic的字符串,其中每个奇数字符都是辅音,每个偶数字符都是元音。虽然我理解这会降低密码的复杂性,但通常更容易记住。现在我想通过生成易于输入的字符串来改进它。

QWERTY Keyboard Layout

例如,虽然* nix新手我总是喜欢基于RHEL的发行版而不是Debian发行版,但主要原因是键入yum的简易性与键入apt[-get]的简易性相比,只是为自己尝试一下

如何实现逻辑以生成易于在QWERTY键盘上键入的字符串?

8 个答案:

答案 0 :(得分:3)

Carpalx对计算typing effort进行了大量研究,其中包含:

  
      
  • 手指行程距离
  •   
  • 手,手指和排罚
  •   
  • 中风路径
  •   

他们研究的结果是Colemak键盘布局,claims to be better than Dvorak

然而,它是从你想要的东西向后写的 - 他们的目标是根据输入找到更好的键盘布局,但你试图根据键盘布局找到简单的输入。

所以 - 即使你可能无法直接使用它,我认为你可能会发现它很有趣(谁知道,如果你的Perl-fu很强大,你可能能够提取和反转算法,因为它是GPL'd)。

答案 1 :(得分:2)

你可以删除用环和小指(q,w,x,z,p)键入的所有字符,然后吐出由左手和右手输入的字符,并在这些字母之间交替。 / p>

答案 2 :(得分:1)

也许您可以使用一些启发式方法来衡量“打字的便利性”。

例如,考虑转到下一个角色时移动手指的成本。这可以是手指需要移动多远,哪个方向等的函数。

当需要切换手指或手时,您还可以增加额外费用。

在花了一些成本后,你可能会找到一个满意的解决方案。

希望有所帮助。

答案 3 :(得分:1)

很好的问题 - 采取上述建议,这里是从键i到键j的距离的公式:

重量=距离* a +开关* b +相同* c + shift * d +怪异* e +开始* f

距离是一个值,其他是0/1值。

距离 - 通过在QWERTY键盘上叠加精细网格获得,查找x,y 并计算距离。距离具有正重量。如果字母组合是使用不同的手(例如aj,sk,wu ......),则距离为零。

开关 - 负重;切换很好

相同 - aq,qa,az,za使用相同的手指。同样是积极的

转变 - 任何有转变的事情都是积极的,真正的坏事

很奇怪 - 我不知道$或〜是坏的,因为你必须要看键盘。

开始 - asdfjkl开始或结束。可能是负面的&amp;很好,因为你的手指在那里休息。

系数 - 只要相对值看似合理,就可以启动它们。 如果你真的想要得到想象 - 让某人输入数十组数字,使用秒表并适合回归模型。

实施 - 说我们有六个字符的密码。

现在我需要从每个字母开始的六个字符的最低值。想象一下列中的N个键的数组。现在想象六列。您的最短密码是通过六列的最短路径(允许循环)。你可能需要添加一些逻辑来消除周期,但这应该是一个很好的第一遍。 (我在这里变得懒惰 - 可能有一个图形理论公式来处理这个问题。)

我敢打赌以前有人这样做过 - 特别是按键部分。

答案 4 :(得分:1)

您可能需要查看principles used in the Dvorak keyboard

密码生成算法中应用的原则是:

  • 应该通过改变手来打字。
  • 使用易于键入的组合。看看Dvorak布局,看看常见的有向图和字母的位置。
  • 只使用底行的一个字母。让它随机!
  • 您可以将比率设为2比1(右手输入2个字母,左手输入1个字母)。
  • 由于这个比例是2比1,你将要用同一只手输入2个连续的字母,这样你就必须确保从键盘外部输入内部。这个原则适用于有向图。

我知道你说它是QWERTY键盘,但在QWERTY键盘上使用这些原理可以给你一些非常好的结果,例如:

  

ktrd,ogkdo(dvorak中的“打字机”)

     

kjg; g; akd; k(仅使用主行)

     

pjedoildupsk(只是遵循原则的随机密码)

所有德沃夏都憎恨,嘘![/ p>

我希望这会有所帮助。

答案 5 :(得分:1)

我把以下一起粉碎了。这是一个黑客工作,但似乎工作得很好。

<?
function Mnemonic($mnemonic)
{
    $result = null;
    $charset = array(str_split('@a3e!1i0ou', 1), str_split('#$*bcdfghjklmnpqrstvwxyz', 1));

    $lastchar = ' ';
    for ($i = 1; $i <= $mnemonic; $i++)
    {
      do {
        $char = $charset[$i % 2][array_rand($charset[$i % 2])];
      } while (!nextkey($lastchar, $char));
      $result .= $char;
    }

    return $result;
}

function nextkey($lastchar, $requestchar)
{
  $map = array();
  $map[] = '!qaz'; // ll
  $map[] = @#wsx1'; // lr
  $map[] = 'ed23'; // lm
  $map[] = '$%^rtfgcvb456'; // li
  $map[] = '&yhnujm7'; // ri
  $map[] = '*()ik89'; // rm
  $map[] = 'olp,.'; // rr
  $map[] = ';[]'; // rl
  $map[] = '!@#$%^&*()[]'; // special chars, don't follow
  $map[] = 'pbvcnmq'; // consonant clusters, don't follwo

  if($lastchar == $requestchar) return true;
  foreach($map as $string)
    if(strpos($string, $requestchar) && strpos($string, $lastchar)) return false;
  return true;
}

printf("%s\n", Mnemonic(8));
?>

答案 6 :(得分:0)

构建一个代表键盘的数据结构,并对用于键入每个字符的行,列,手和手指进行编码。编写一个函数,当出现一个字符时,根据您开发的灵活规则提供“易于键入的下一个”字符列表。它可以依赖另一个计算键之间距离的函数。

就我个人而言,我没有发现用同一只手两次输入字母的速度很慢:只有当前一个字母使用过于接近的手指时才很难。例如,XQ很难打字,因为我的手必须向上移动以处理键入它们所需的相邻手指。但我觉得BQ很难打字,因为虽然我的食指还在B上工作,但是我的小指可以前往Q.

输入AW比QS更容易,因为无名指更长,因此当小指在A上时,自然适合W,处于接近静止位置,而QS需要一小段小指和无名指同时发生冲突的肌肉紧缩。

如果你开始建立每个字母对彼此字母的地图,你很快就会找到一种合理的方式来表示容易或困难的各个方面。推广我的XQ / BQ示例,您可以进行一行更改需要2个或更多手指的距离,2行更改需要3个手指的距离,3行更改(数字,可能)需要交替的手。

我也注意到WD和IL之间的距离略长于SE和KO也会改变难度,因为按键位置略有锯齿状。

通过一些分析(我建议使用Excel来“映射”打字难度)我相信你可以想出一个可以帮助你构建易于输入的单词的算法。

如果可能的话,尝试投入至少一个数字,并考虑使用空格。

答案 7 :(得分:0)

如果您实现此功能,请在确定从一个字符移动到另一个字符的“成本”时考虑用户的区域设置。如果用户使用不同的键盘布局,则易于输入的密码可能会变得相当麻烦。在一种语言的键盘上可能很容易访问的某些键可能无法在另一种语言的键盘上使用,而无需额外的修饰键(shift,meta等)。

为了保持这个想法的通用性,我建议忽略哪个字符属于哪个键,而是将键视为具有行和列的数组。每行通常偏离前一个大约1/3的键宽度。考虑到这一点,计算任意两个任意键之间的距离应该不难:

# Key at top left corner is {0, 0}
key1 @ {x1, y1}
key2 @ {x2, y2}

xdistance = absolute_value(x2 - x1)
ydistance = absolute_value(y2 - y1)

if y1 > y2
  xdistance += (1/3 * ydistance)
else
  xdistance -= (1/3 * ydistance)

total_distance = square_root(xdistance^2 + ydistance^2)

生成符合您的长度和“易于键入”要求的一系列关键位置,然后使用用户的当前键映射将这些索引重新映射为字符。