33

是否存在更易于阅读的字母数字子集?特别是,是否存在具有较少视觉模糊字符的子集,并且通过删除(或等同)某些字符,我们可以减少人为错误?

我知道“视觉上模棱两可”的表达方式有些古怪,但很明显 D、O 和 0 都很相似,1 和 I 也很相似。我想最大化字母数字集的大小,但尽量减少可能被误解的字符数。

我知道这样一个集合的唯一先例是加拿大邮政编码系统,它删除了字母 D、F、I、O、Q 和 U,并且创建该子集是为了帮助邮政系统的 OCR 过程。

我最初的想法是只使用大写字母和数字,如下所示:

一种
B = 8
C = G
D = 0 = O = Q
E = F
H
我 = J = L = T = 1 = 7
K = X
米
ñ
磷
R
S = 5
U = V = Y
W
Z = 2
3
4
6
9

这个问题可能很难与给定的字体分开。所选字体中字符的独特性可能会显着影响任何两个字符的潜在视觉模糊性,但我预计在大多数现代字体中,上述等同的字符将具有足够相似的外观以保证它们等同。

我会很感激上面的想法——上面的方程是否合适,或者是否有更多的字符应该被等同起来?小写字符会更合适吗?

4

10 回答 10

16

出于类似的原因(例如,用于对密钥进行编码等),我需要替换十六进制(以 16 为底),我能想到的最好的方法是以下 16 个字符集,可用作十六进制的替换:

0 1 2 3 4 5 6 7 8 9 A B C D E F     Hexadecimal
H M N 3 4 P 6 7 R 9 T W C X Y F     Replacement

在替换集中,我们考虑以下内容:

所有使用的字符都有主要的区别特征,只有在真正糟糕的字体中才会被省略。

省略元音 AEIOU 以避免意外拼写单词。

完全避免在某些字体中可能非常相似或相同的字符集(根本不使用任何集中的字符):

0 O D Q 
1 I L J
8 B 
5 S
2 Z

通过完全避免这些字符,希望用户将输入正确的字符,而不是试图纠正错误输入的字符。

对于不太相似但可能令人困惑的字符集,我们在每组中只使用一个字符,希望是最有特色的:

Y U V 

这里使用 Y,因为它始终具有较低的垂直部分,并且衬线字体中的衬线

C G         

这里使用了 C,因为似乎不太可能将 C 输入为 G,反之亦然

X K         

这里使用 X,因为它在大多数字体中更加一致

F E         

这里使用 F,因为它不是元音

在这些相似集合的情况下,集合中的任何字符的输入都可以自动转换为实际使用的字符(每个集合中列出的第一个)。请注意,如果可能使用十六进制输入,则 E 不能自动转换为 F(见下文)。

请注意,替换集中仍有发音相似的字母,这几乎是不可避免的。大声朗读时,应使用拼音字母。

在替换集中使用标准十六进制字符时,它们用于相同的 base-16 值。理论上可以支持十六进制和替换字符的混合输入,前提是 E 不会自动转换为 F。

由于这只是一个字符替换,因此应该很容易转换为十六进制。

大写似乎最适合输出的“规范”形式,虽然小写也看起来合理,除了“h”和“n”,在大多数字体中应该仍然相对清晰:

h m n 3 4 p 6 7 r 9 t w c x y f

输入当然可以不区分大小写。

base 32 有几个类似的系统,请参阅http://en.wikipedia.org/wiki/Base32但是这些显然需要引入更多外观相似的字符,以换取每个字符额外增加 25% 的信息。

显然,以下集合也用于以 24 为基数的 Windows 产品密钥,但同样具有更多相似的字符:

B C D F G H J K M P Q R T V W X Y 2 3 4 6 7 8 9
于 2014-12-13T13:16:45.657 回答
14

主要从@rwb提到的这个ux线程中汲取灵感,

  • 几个 程序使用类似的东西。您帖子中的列表似乎与这些程序中使用的列表非常相似,我认为对于大多数用途来说应该足够了。您可以添加总是添加冗余(纠错)以“原谅”小错误;但是,这将要求您将代码间隔开(请参阅汉明距离)。
  • 没有关于派生列表中使用的特定方法的参考,除了与人类的反复试验(这对于非 ocr 非常有用:您的用户人类)
  • 使用字符分组(例如,5 个组)来增加上下文(“5 个组中的第二个中的第一个字符”)可能是有意义的
  • 歧义可以通过使用完整名词(来自几乎没有相似之处的字典;单词编辑距离在这里可能有用)而不是字符来消除。人们可能会将“1”与“i”混淆,但很少有人会将“one”与“ice”混淆。
  • 另一种选择是将您的代码变成可以大声读出的(假)单词。马尔可夫模型可以帮助你。
于 2012-09-23T12:03:01.447 回答
9

我的 23 个明确字符是:

c,d,e,f,h,j,k,m,n,p,r,t,v,w,x,y,2,3,4,5,6,8,9

我需要一组明确的字符供用户输入,而且我找不到其他人已经生成了符合我标准的字符集和规则集的任何地方。

我的要求:

  1. 没有大写字母:这应该在 URI 中使用,并且由可能没有很多打字经验的人输入,对于他们来说,即使是 shift 键也会减慢他们的速度并导致不确定性。我也希望有人能够说“全小写”以减少不确定性,所以我想避免大写字母。

  2. 很少或没有元音:避免产生粗话或令人惊讶的词的简单方法是简单地省略大多数元音。我认为保留“e”和“y”是可以的。

  3. 始终如一地解决歧义:我愿意使用一些歧义字符,只要我只使用每组中的一个字符(例如,在小写 s、大写 S 和五个中,我可能只使用五个);这样,在后端,我可以用他们组中的一个正确字符替换这些模棱两可的字符中的任何一个。因此,在我在我的数据库中查找它的匹配项之前,输入字符串“3Sh”将被替换为“35h”。

  4. 只需要创建标记:我不需要像 base64 或 base32 那样对信息进行编码,所以我的集合中的确切字符数并不重要,除了我希望尽可能大。它只需要对生成随机 UUID 类型的 id 令牌有用。

  5. 强烈偏爱非歧义性:我认为与某人必须输入更长的令牌相比,输入令牌并出现问题的成本要高得多。当然,有一个权衡,但我更喜欢简洁而不是模糊。

我确定的易混淆的字符组:

  • A/4
  • b/6/G
  • 8/B
  • 转/转
  • 女/女
  • 9/g/q
  • i/I/1/l/7 - 太模糊而无法使用;请注意,欧洲的“1”可能看起来很像许多人的“7”
  • k/K
  • o/O/0 - 太模糊而无法使用
  • 纸币/纸币
  • 秒/秒/5
  • v/V
  • 带W/W
  • X/X
  • 是/是
  • z/Z/2

明确的字符:

我认为这只剩下 9 个完全明确的小写/数字字符,没有元音:

d,e,h,j,m,n,r,t,3

从每个模棱两可的组中添加一个字符(并尝试更喜欢看起来最明显的字符,同时避免大写),有 23 个字符:

c,d,e,f,h,j,k,m,n,p,r,t,v,w,x,y,2,3,4,5,6,8,9

分析:

使用经验法则,即具有 N 种可能性的数值等效范围的 UUID 足以避免 sqrt(N) 实例的冲突:

  • 使用此字符集的 8 位 UUID 应该足以避免大约 300,000 个实例的冲突
  • 使用此字符集的 16 位 UUID 应该足以避免大约 800 亿个实例的冲突。
于 2019-09-25T12:26:47.393 回答
3

您所寻求的是明确的、高效的人机代码。我推荐的是用文字(有意义的)单词,特别是名词对整个数据进行编码。

我一直在开发一种软​​件来做到这一点——而且效率最高。我称之为WCode
从技术上讲,它只是 Base-1024 编码 - 在其中您使用单词而不是符号。

以下是链接:
演示文稿: https ://docs.google.com/presentation/d/1sYiXCWIYAWpKAahrGFZ2p5zJX8uMxPccu-oaGOajrGA/edit
文档: https ://docs.google.com/folder/d/0B0pxLafSqCjKOWhYSFFGOHd1a2c/edit
项目: https:// /github.com/San13/WCode(请稍候,我正在上传...)

于 2012-09-24T20:56:06.830 回答
3

如果您可以选择仅使用大写字母,我会根据用户通常输入错误的字符创建此集合,但这完全取决于他们阅读文本时使用的字体。

要使用的字符: A C D E F G H J K L M N P Q R T U V W X Y 3 4 6 7 9

要避免的字符:

B similar to 8
I similar to 1
O similar to 0
S similar to 5
Z similar to 2
于 2020-04-05T14:30:00.333 回答
2

这将是 OCR 中的普遍问题。因此,对于控制 OCR 编码的端到端解决方案 - 已经开发了专门的字体来解决您提到的“视觉模糊”问题。见:http ://en.wikipedia.org/wiki/OCR-A_font

作为附加信息:您可能想了解 Base32 编码 - 其中不使用数字“1”的符号,因为它可能会将用户与字母“l”的符号“混淆”。

于 2012-08-12T09:16:20.760 回答
2

对于人类来说,看起来明确的字母对于光学字符识别 (OCR) 来说也是明确的。通过删除所有对 OCR 感到困惑的字母对,可以获得:

 !+2345679:BCDEGHKLQSUZadehiopqstu

https://www.monperrus.net/martin/store-data-paper

于 2020-05-16T16:40:07.877 回答
1

这取决于你希望你的集合有多大。例如,只有集合 {0, 1} 可能会很好地工作。同样只有一组数字。但可能你想要一个大约是原始字符集一半大小的集合。

我没有这样做,但这里有一个建议。选择一种字体,选择一组初始字符,然后编写一些代码来执行以下操作。绘制每个字符以适应 n×n 的黑白像素正方形,n = 1 到(比如说)10。从边缘切掉所有全白的行和列,因为我们只对黑色区域。这为您提供了每个字符的 10 个代码列表。通过这些代码中有多少不同来测量任何两个字符之间的距离。估计您的应用程序可接受的距离。然后对相距很远的一组字符进行蛮力搜索。

基本上,使用脚本来模拟对角色的眯眼,看看您仍然可以区分哪些角色。

于 2012-09-16T16:59:49.827 回答
1

这是我编写的一些python,用于使用上述字符系统对整数进行编码和解码。

def base20encode(i):
    """Convert integer into base20 string of unambiguous characters."""
    if not isinstance(i, int):
        raise TypeError('This function must be called on an integer.')     
    chars, s = '012345689ACEHKMNPRUW', ''
    while i > 0:
        i, remainder = divmod(i, 20)
        s = chars[remainder] + s
    return s


def base20decode(s):
    """Convert string to unambiguous chars and then return integer from resultant base20"""
    if not isinstance(s, str):
        raise TypeError('This function must be called on a string.')
    s = s.translate(bytes.maketrans(b'BGDOQFIJLT7KSVYZ', b'8C000E11111X5UU2'))
    chars, i, exponent = '012345689ACEHKMNPRUW', 0, 1
    for number in s[::-1]:
        i += chars.index(number) * exponent
        exponent *= 20
    return i


base20decode(base20encode(10))
于 2017-09-15T20:10:42.890 回答
-1

base58:123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz

于 2020-04-23T13:35:01.953 回答