【问题标题】:Caesar cipher with all Unicode printable characters具有所有 Unicode 可打印字符的凯撒密码
【发布时间】:2019-06-13 14:39:37
【问题描述】:

我想创建一个凯撒密码,它可以对整个 Unicode(私人使用区域除外)中的 Unicode 可打印字符(单和多码点字素簇、表情符号等)进行编码/解码。最好是使用所有可打印字符的列表。

注意:尽管我想创建一个凯撒密码,但这实际上与加密无关。问题是关于调查 unicode 的属性。

我发现了这些问题:

What is the range of Unicode Printable Characters?

Cipher with all unicode characters

但我没有得到我想要的答案。

注意: 如果您给出编码答案,我最感兴趣的解决方案是 使用 python3 或 perl6,因为它们是我的主要语言。

最近,我接到了一项任务,要编写凯撒密码,然后对英文文本进行编码和解码。

我通过使用字符串库的内置 string.printable 常量在 python 中解决了它。这是常量的打印输出: (我使用了 Visual Studio 代码)

[查看下面的python代码和结果]

文档说: ''' 被认为是可打印的 ASCII 字符串。这是数字、ascii_letters、标点符号和空格的组合。 ''' https://docs.python.org/3.6/library/string.html#string-constants

我想知道如何创建一个凯撒密码,该密码可以编码/解码您可以从 unicode 代码点生成的所有可能的可打印字符(假设您拥有所有必要的字体来查看那些应该在屏幕上可见的字体)。 H1>

这是我对它的含义的理解 可以打印的字符:

当我取上面的python字符串常量时, 并用左或右箭头键遍历它 在键盘上,我需要 100 次敲击才能得到 到最后(与字符数相同)。 好像有一对一的 可打印之间的对应关系 字符,并且可以一键遍历。

现在考虑这个字符串:

"??????‍????‍??????‍????ij क्षि ????”

基于pythons string.printable 常量, 在我看来,这个字符串由 以下 7 个可打印字符: (您可以在以下位置查找各个代码点:https://unicode-table.com/en/

1(家庭)2(拉丁文小连字 Ij) 3(回车) 4(天城文 kshi) 5(空格) 6(零宽度不间断空格) 7(黑桃 A)

????‍????‍????‍???? 代码点:128104 8205 128105 8205 128103 8205 128102 (参考:https://emojipedia.org/family-man-woman-girl-boy/

(拉丁文小连字 Ij) ij 代码点:307

(回车) 代码点:13

(天城文 kshi) क्षि 代码点:2325 2381 2359 2367
(见本页:http://unicode.org/reports/tr29/) (代码点似乎是十六进制而不是数字)

(空格) 代码点:32

(零宽度不间断空格) 代码点:65279 (又名 U+FEFF 字节顺序标记 (BOM)) (https://en.wikipedia.org/wiki/Byte_order_mark)

(扑克牌黑桃 A) ??? 代码点:127137

当我粘贴这个 将字符串输入记事本,并尝试用箭头键遍历它, 我最终使用了 10 个击键而不是 7 个, 因为家庭表情符号需要 4 击键 (可能是因为记事本无法处理零宽度连接器, 代码点:8205,当然记事本不能显示家族字形)。 另一方面,当我将字符串发布到谷歌搜索时, 我可以用 7 笔遍历整个字符串。

然后我尝试创建字符串 在 Perl6 中看看 Perl6 的字形是什么 意识会使字符串:

(我使用 Atom 编辑器)

[参见下面的 perl6 代码和结果]

perl6 认为梵文 kshi 字符 क्षि (4 个代码点) 实际上是 2 个字素,每个字素有 2 个代码点。 即使它可以表示为两个字符, 如上面的列表所示, 我认为这是一个错误。 Perl6 应该是字素 知道,甚至我的 Windows 记事本(和谷歌搜索) 认为它是单个字素/字符。

基于 2 个字符串, 的实际定义 一个可打印的字符似乎是这样的: '它是可以遍历的 unicode 代码点的任意组合 只需按一下键盘上的向左或向右箭头键 理想情况下”。

“在理想情况下”意味着 你正在使用的环境,可以这么说, 像谷歌搜索一样: 也就是说,它识别例如一个表情符号 (4 人家庭)或字素簇 (梵文字符) 作为一个可打印的字符。

3 个问题:

1: 以上是对它的含义的公平定义吗 成为 unicode 中的可打印字符?

2: 不管你是否接受这个定义, 你知道任何可打印字符的列表吗 涵盖当前使用的 unicode 平面和可能的 字形簇,而不仅仅是 100 个 ASCII 字符 python字符串库有 (如果我有这样的列表,我想我可以创建一个密码 很容易)?

3: 鉴于这样的列表不存在,并且您 接受定义, 您将如何创建这样一个列表 我可以创造一个凯撒密码 可以加密任何/所有可打印的 给定以下 4 个条件的字符?

注意:这 4 个条件只是 我想象的需要一个适当的 凯撒密码。

条件a

要加密的字符串将 是一个由标准组成的有效 utf8 字符串 unicode 代码点(没有未分配或私人使用区域 代码点)

条件b

加密的字符串也必须是有效的 由标准组成的 utf8 字符串 unicode 代码点。

条件c

你必须能够遍历加密字符串 使用相同的笔画数 键盘上的向左或向右箭头键为 原始字符串 (给定如上所述的理想情况)。 这意味着两者 男人女人男孩女孩家庭表情符号 和梵文字符, 编码时,必须分别对应 恰好是另一个可打印字符,而不是一组 的“无意义”代码点 箭头键将解释为不同的字符。 这也意味着单个代码点字符可以 可能被转换为多码点字符 反之亦然。

条件d

与任何加密/解密算法一样, 要加密的字符串和 已解密的字符串 (最终结果)必须 包含完全相同的代码点 (两个字符串必须相等)。

# Python 3.6:
import string           
    # build-in library
print(string.printable)      
print(type(string.printable))   
print(len(string.printable))    
    # length of the string (number of ASCII characters)


#perl6
use v6;

my @ordinals = <128104 8205 128105 8205 128103 8205 128102>;    
    #array of the family codepoints
@ordinals.append(<307 13 2325 2381 2359 2367 32 65279 127137>); 
    #add the other codepoints
my $result_string = '';
for @ordinals {
    $result_string = $result_string ~ $_.chr;  
}
    # get a string of characters from the ordinal numbers
say @ordinals;              # the list of codepoints
say $result_string;             # the string
say $result_string.chars;       # the number of characters.
say $result_string.comb.perl;   # a list of characters in the string

python 结果:

0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&'()*+,-./:;?@[]^_`{|}~

类'str'

100

perl6 结果:

[128104 8205 128105 8205 128103 8205 128102 307 13 2325 2381 2359 2367 32 65279 127137]

??????‍????‍??????‍??????ij क्षि ????

8

("????‍????‍????‍????", "ij", "\r", "क्", "षि", " ", "", " ????").Seq

【问题讨论】:

  • 嗯,我刚刚在 10 分钟前发布了这个问题,而且我已经有了 -2。我的问题有什么问题?
  • 请注意,Unicode 字素簇的数量是无限的,因为簇可以包含任意数量的组合标记。所以你的密码可能应该基于单个代码点。
  • 我的建议:编码unicode字符串,然后用BASE64编码。然后你有 64 个符号并在它们上使用凯撒。无论如何:这是一个弱加密。不用于实际情况。
  • 文本的复杂性促使现代密码不处理字符。它们处理输入和输出的字节。如果输入是文本,则必须告知接收者字符编码。如果必须以文本形式进一步处理输出,则使用 Base64 或类似的。期望密码的输出看起来像文本通常不是目标。
  • @GiacomoCatenazzi 一般来说,组合字符的数量没有限制。 stream-safe text format 指定最多 30 个非初学者,但这种格式不是强制性的。

标签: python unicode raku caesar-cipher


【解决方案1】:

TL;DR 我认为您的问题是合理的,值得得到比我目前所写的更好的答案。聊聊吧。


出于多种原因,我认为没有人可以根据您列出的要求创建凯撒密码。

但如果您的目标真的是“研究 Unicode 的属性”而不是创建密码,那么这可能并不重要。

当然,我可能只是缺乏想象力,或者只是无法理解 Unicode,尽管我花了数年时间努力解决它。

如果您通过 cmets 批评我在下面的解释中的技术方面,我会尝试改进它,希望我们都能边走边学。 TIA。

“具有所有 Unicode 可打印字符的凯撒密码”

这是您在标题中的简洁表述。

唯一有问题的部分是“Caesar”、“cipher”、“all”、“Unicode”、“printable”和“characters”。让我们通过它们。

凯撒密码

凯撒密码是一种特别简单的单字母密码。 Unicode 不是一个大的单一字母表。但也许您可以将其代码点的一个子集视为它们。

我想说这就是 SO Cipher with all unicode characters 的全部意义所在。

您目前拒绝了这一点,并引入了一堆额外的方面,这些方面要么是不可能的,要么是非常困难的。

忽略您研究 Unicode 属性的优先级,如果您改用常规 ASCII 密码,这将是有意义的。或者也许回到那个 所有 unicode 字符的密码 SO 并从他们离开的地方继续,也许注意到,根据a comment on that SO 他们显然只是停在 BMP 平面:

请注意,您只使用 BMP 代码点(即从 U+0000 到 U+FFFF)。 Unicode 的范围从 U+0000 到 U+10FFFF,因此您丢失了大约一百万个代码点 :)

所以也许你可以做得更好。从创建密码的角度来看,我认为这不值得,但它可能是为了更多地了解 Unicode 的属性。

密码

@TomBlodget 在their comment on your question 中指出:

文本的复杂性促使现代密码不处理字符。它们处理输入和输出的字节。如果输入是文本,则必须告知接收者字符编码。如果必须以文本形式进一步处理输出,则使用 Base64 或类似方法。期望密码的输出看起来像文本通常不是目标。

如果您想要 Unicode 密码的通用解决方案,请遵循 Tom 的食谱。

全部

在评论您关于字形数量的问题时,@nwellnhof 指出:

有无数个

但是你也很合理地回答说在任何给定的文本中只会有一个有限的数字; Unicode 的意图是,如果给定退化的输入,符合 Unicode 的软件可能/将生成 mojibake 结果(其中被视为退化的东西在某种程度上可以在 Unicode 更新中进行改进);这就是您希望继续进行的基础。

这是一个合理的回答,但即使限制为“所有非退化的”和“只有那些可能出现在现实生活中的”,你仍然不能拥有“全部”,因为仍然存在无限数量的良构和可能合理的字符。

我真的应该在这里插入一些计算来为问题设置一些界限。 “实际上无限”是一万亿吗?为什么?之类的东西。但在深入研究之前,我会等待 cmets。

让我们假设它是一万亿,这不是问题,然后继续前进。

Unicode

Unicode 非常复杂。

你的任务是生成一个凯撒密码,这是一件非常简单的事情。

除非你非常注重保持简单,否则它们真的不能很好地混合。

但是您想研究 Unicode 的属性。所以也许你想涉足所有的复杂性。但接下来的问题是,你想花多少年去探索打开这个潘多拉魔盒的后果? (我已经断断续续地研究 Unicode 十年了。这很复杂。)

可打印

您链接到 SO 问题“Unicode 可打印字符的范围是多少?”。这包括一个答案:

您对 Unicode 了解得越多,就越能意识到人类书写系统的多样性和不可思议的怪异程度。特别是一个特定的“字符”是否可打印并不总是显而易见的。

但你大概读到了,并拒绝被吓倒。这既令人钦佩又自找麻烦。例如,它似乎驱使您将“可打印”定义为“需要一次或多次击键才能遍历”之类的东西,这非常令人担忧,以至于很难知道从哪里开始——所以我会一直强调这一点。回答。

字符

鉴于您的目标是编写凯撒密码,这是一种数千年前用于作用于角色的密码,因此您专注于“用户对角色的看法”是有道理的。

根据Unicode's definition,这被称为“字形”。

您的一个示例字符清楚地表明了“用户认为的字符”(字素)和代码点(Python 认为的字符)之间的区别有多大问题:

print('क्षि'[::-1])
िष्क

这显示了用梵文编写的单个“字符”(单个字素)的修饰,根据维基百科,梵文是“世界上使用和采用最多的书写系统之一”。

(或者,如果我们想忽略这种破坏更经常影响的地球的一半,而只关注那些认为自己安全的人:

print('??'[::-1])
??

这是一个国家的国旗变成另一个国家的国旗。幸运的是,标志很少出现在文本中——尽管现在文本越来越像我正在写的这个文本一样是任意的 Unicode 文本——而且标志字符并不那么重要,而且英国和保加利亚都是欧盟的成员,所以它可能不太重要就像扰乱十亿印度人的文字一样糟糕。)

字形

所以你很合理地想,“也许 Perl 6 会有所帮助”。

引用UAX#29,关于“Unicode 文本分割”的 Unicode 附件文档:

本文档定义了字素簇的默认规范。

Perl 6 已经实现了字素集群机制。它原则上可以以多种方式进行集群,但目前它已实现默认规范。这就是让 Perl 6 避免 Python 在上面犯的错误的原因。

但 Unicode 文档仍在继续:

[字素集群的规范]可以针对特定的语言、操作或其他情况进行定制。

因此,如果“字符”是指“用户认为的字符”,那么您不能只盯着某些文本(或将其提供给某些软件)并说出其中包含哪些“字符”。

情况越来越糟了……

击键

"?‍?‍?‍?ij क्षि ?" ... 记事本 ... 10 次击键 ... google 搜索 ... 7 次 ... Perl6 ... Atom 编辑器 ... perl6 认为 क्षि ...实际上是 2 个字形 ...我认为这是一个错误 ...记事本(和谷歌搜索)认为它是单个字形/字符

对我来说,谷歌搜索需要 10 次击键——因为这与谷歌搜索无关,而是我系统的各个方面,包括我正在使用的网络浏览器 (Firefox) 和其他详细信息。

一些编辑器是可配置的,因此将光标悬停在“क्षि”(或“fi”)上将是 1 次或 2 次击键,具体取决于您的配置方式和/或您指定的文本编写语言。对我来说,在 Linux Mint 上使用 Firefox 编辑此 SO 答案,需要 2 次击键才能将光标悬停在 क्षि 上。

默认情况下,Perl 6 正确地将 'क्षि' 的 .chars 结果报告为 2,因为这是 Unicode 根据默认字形聚类规范所说的。 (“Extended Grapheme Clusters”。)这恰好与 Linux Mint 上的 Firefox 编辑此 SO 答案的内容相匹配,因为星星排成一列,现在是星期天。

记事本或其他软件合理地只需一次按键即可将光标悬停在 क्षि 上,而其他编辑器合理地需要两次,因为根据 Unicode 规范,两者都是合理的:

箭头键移动 ...可以使用特定字体的特定知识以更精细的方式移动,在编辑单个组件有用的情况下

我的强调已添加。 Unicode 由软件决定光标的移动方式。

您的问题

1:以上是对 unicode 中可打印字符的含义的公平定义吗?

我不这么认为。希望上述内容能够解释原因,或者至少为您指明需要研究(一年或三年)以了解原因的方向。

2:...您知道任何涵盖当前使用的 unicode 平面和可能的字素簇的可打印字符列表...

有如此大量的“可能的字素簇”可以合理地发生,即使排除退化的代码点组合也会给您留下一个有效的无限列表。

任何人可能创建的任何小子集都不会是规范的,因为 Unicode 联盟不会祝福它,人们会争论应该包括什么。

3:...您将如何创建这样一个列表,我可以使用该列表创建一个凯撒密码,该密码可以在以下 4 个条件下加密任何/所有可打印字符?

首先,您的条件过于艰苦。请参阅下一节。

但是即使你放弃了那些太难的东西,它仍然太难了,结果也太无趣了,做任何事情都值得。

4:如果您认为创建这样的列表是一个糟糕的想法,您将如何创建密码?

如果是我并且它必须是凯撒密码,我会让它只处理字节,根据汤姆在这个答案开头的评论。

您的条件

要加密的字符串将是一个有效的 utf8 字符串,由标准 unicode 代码点组成(没有未分配或私人使用区域代码点)

它需要更多限制,但可以合理地说它需要是一个有效的 Unicode 字符串。如果你想坚持它是 utf8 也可以。

加密字符串也必须是由标准 unicode 代码点组成的有效 utf8 字符串

当然。

您必须能够使用与原始字符串相同的笔画数来遍历加密字符串

您可以将其用于一小部分 Unicode 字符。但是……

这意味着[原始版本和编码版本的一次按键] 梵文字符 [क्षि]

...不是一个合理的要求。

如果您为您的密码编写了一个字素聚类的自定义实现,该实现是用于控制光标的字素聚类实现的忠实副本,您可以确保给定文本的相同字素聚类(字符)解释。

但随后您必须维护这两个代码库以使它们保持同步。这仅适用于一种特定的系统配置。

这将是一个荒谬的痛苦。而对于零或至多微不足道的增益。

要加密的字符串和已解密的字符串(最终结果)必须包含完全相同的代码点(这两个字符串必须相等)。

所以,没有标准化。

这排除了所有 Perl 6 的字素感知好东西。

再一次,你无论如何都需要放弃关注字素,因为它们实际上是无限多的。

结论

我的回答只涉及它所涵盖的主题,并且可能包含很多错误。如果你批评它,我会尝试改进它。

【讨论】:

  • 感谢您的回答! (抱歉回复晚了。忙碌的一周)。我承认我的“穿越”想法很糟糕。我需要更好地定义性格的含义。一个上帝的起点可能是字体。以 google NOTO 字体为例。我的目标很接近:识别屏幕上可以看到的所有字符并为它们提供字体,这样人们就可以避免“豆腐”......
  • ...您写道:“...实际上仍有无限数量的格式良好且可能合理的字符。”字体不包括空格之类的东西,但除此之外,像 google NOTO 这样的项目是如何不完整的?他们遗漏了什么?原则上,它们是给定 unicode 版本的有限集。
  • @Arimaafan NOTO 并不完整。它确保所有字素都显示没有豆腐。他们都是。我忽略了字体和 gyphs 的问题,因为 A)你写了“假设你有所有必要的字体来查看那些应该在屏幕上可见的字体”并且 B)它们不是问题。
  • @Arimaafan 我写过“我真的应该在这里插入一些计算来为这个问题设置一些界限。“实际上是无限的”是一万亿吗?......但在深入研究之前,我会等待 cmets。 "现在你已经评论了我愿意看看这个。下周我要看的第一个问题是有多少相对通用的组合器。 say "A keycap grapheme: a\c[Combining Diaeresis, Combining Enclosing Keycap]" 显示 A keycap grapheme: ä⃣。键帽组合器看起来很通用。如果有 10 个这样的通用组合器,一个填写好的字母表将包含大约十亿个字素。
  • @Arimaafan 似乎有数百甚至数千个可以合理地被视为“通用组合器”的东西。这当然意味着数以万亿计的组合,即使在标准化之后也是如此。我在探索时阅读的资源显示了许多其他棘手的问题,如果有人要尝试像您描述的那样远程创建密码。所以我要在这一点上保释。在下一条评论中,我将留下指向 Unicode 网站的链接和导致我得出这个结论的 SO 问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-07
  • 2020-05-31
  • 2014-02-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多