用于使用IETF语言标签标记人类语言的工具
项目描述
Langcodes:语言代码库
langcodes 了解语言。它知道指代它们的标准化代码,例如 en
代表英语,es
代表西班牙语,hi
代表印地语。
这些是 IETF 语言标签。你可能知道它们以前的名称,ISO 639 语言代码。IETF 为向后兼容性和支持在 ISO 标准中找不到的语言变体做了一些重要工作。
你可能觉得 langcodes 解决了一个相当无聊的问题。在某种程度上,这是正确的。有时候你有一个无聊的问题,当有一个库为你解决它时,那真是太好了。
但这里隐藏着一个有趣的问题。你如何处理语言代码?你怎么知道两个不同的代码代表相同的事物?你的代码应该如何表示代码之间的关系,如下所示?
eng
等同于en
。fra
和fre
都等同于fr
。en-GB
可能会被写成en-gb
或en_GB
。或者 'en-UK',这是错误的,但应被视为相同。en-CA
与en-US
不完全等同,但它真的很接近。en-Latn-US
等同于en-US
,因为书面英语必须使用拉丁字母才能被理解。ar
和arb
的区别是 "阿拉伯语" 和 "现代标准阿拉伯语" 之间的区别,这可能对你来说并不重要。- 你会在维基词典中看到标注为
cmn
的普通话,但许多其他资源会将同样的语言称为zh
。 - 中文在不同地区使用不同的书写系统。一些软件区分书写系统,其他软件区分地区。结果是,
zh-CN
和zh-Hans
可以互换使用,zh-TW
和zh-Hant
也是如此,尽管偶尔你需要其他不同的,如zh-HK
或zh-Latn-pinyin
。 - 印度尼西亚语(
id
)和马来西亚语(ms
或zsm
)是相互理解的。 jp
不是一个语言代码。(日语的语言代码是ja
,但人们常常将其与日本的国代码jp
混淆。)
了解这些的一个方法是通过阅读 IETF 标准,以及 Unicode 技术报告。另一个方法是使用一个库为你实现这些标准和指南,这就是 langcodes 所做的。
当你处理这些简短的语言代码时,你可能想看到在语言中该语言被称为什么:在英语中,fr
被称为 "French"。这种语言不一定是英语:fr
在法语中被称为 "français"。langcodes 的补充 language_data
提供了这些信息。
langcodes 由 Elia Robyn Lake(别名 Robyn Speer)维护,并以 MIT 许可证发布为免费软件。
实现的标准
尽管这并不是使用它的唯一原因,但 langcodes 会让你更加符合首字母缩略词规范。
langcodes 实现 BCP 47,这是 IETF 关于语言标签的最佳当前实践。BCP 47 也称为 RFC 5646。它包含 ISO 639,并与其向后兼容,它还实现了来自 Unicode CLDR 的建议。
如果你安装了 language_data
,langcodes 还可以引用一个语言属性和名称数据库,该数据库由 Unicode CLDR 和 IANA 子标签注册表构建。
总结来说,langcodes接收语言代码并对它们做正确的事,如果你想确切地知道什么是正确的事,有一些文档你可以去阅读。
文档
标准化语言标签
此函数以多种方式对标签进行标准化。
它将过长的标签替换为其最简版本,并按照BCP 47的约定格式化它们
>>> from langcodes import *
>>> standardize_tag('eng_US')
'en-US'
它移除与语言冗余的脚本子标签
>>> standardize_tag('en-Latn')
'en'
如果可能,它将已弃用的值替换为其正确版本
>>> standardize_tag('en-uk')
'en-GB'
有时这涉及到复杂的替换,例如将塞尔维亚-克罗地亚语(sh
)替换为拉丁语塞尔维亚语(sr-Latn
),或者整个标签sgn-US
替换为ase
(美国手语)。
>>> standardize_tag('sh-QU')
'sr-Latn-EU'
>>> standardize_tag('sgn-US')
'ase'
如果macro为True,则使用宏观语言代码作为该宏观语言中最常见的标准化语言的替换
>>> standardize_tag('arb-Arab', macro=True)
'ar'
即使macro为False,它也会缩短包含宏观语言和语言的标签
>>> standardize_tag('zh-cmn-hans-cn')
'zh-Hans-CN'
如果标签无法根据BCP 47进行解析,这将引发LanguageTagError(ValueError的子类)
>>> standardize_tag('spa-latn-mx')
'es-MX'
>>> standardize_tag('spa-mx-latn')
Traceback (most recent call last):
...
langcodes.tag_parser.LanguageTagError: This script subtag, 'latn', is out of place. Expected variant, extension, or end of string.
语言对象
此包定义了一个名为Language的类,它包含解析语言标签的结果。语言对象有以下字段,其中任何一个都可能未指定
- language:语言本身的代码。
- script:正在使用的书写系统的4位代码。
- territory:使用该语言的国家或类似地区的2位或3位代码。
- extlangs:一个语言代码列表,该代码跟在语言代码之后。(这是允许的语言代码语法,但已弃用。)
- variants:用于特定语言使用变体的代码,这些变体未涵盖script或territory代码。
- extensions:附加到语言代码上的信息,用于某些特定系统,例如Unicode排序顺序。
- private:以
x-
开头的代码,没有定义的含义。
Language.get
方法将字符串转换为Language实例,而Language.make
方法则从其字段创建Language实例。这些值被缓存,以便再次调用Language.get
或Language.make
时,使用相同的值返回相同的对象,以提高效率。
默认情况下,它将替换非标准和过长的标签,就像它正在解释它们一样。要禁用此功能并获取语言标签中实际出现的代码,请使用normalize=False选项。
>>> Language.get('en-Latn-US')
Language.make(language='en', script='Latn', territory='US')
>>> Language.get('sgn-US', normalize=False)
Language.make(language='sgn', territory='US')
>>> Language.get('und')
Language.make()
以下是替换非标准标签的一些示例
>>> Language.get('sh-QU')
Language.make(language='sr', script='Latn', territory='EU')
>>> Language.get('sgn-US')
Language.make(language='ase')
>>> Language.get('zh-cmn-Hant')
Language.make(language='zh', script='Hant')
使用str()
函数在Language对象上将其转换回其标准字符串形式
>>> str(Language.get('sh-QU'))
'sr-Latn-EU'
>>> str(Language.make(territory='IN'))
'und-IN'
检查有效性
语言代码是有效的,当IANA为其每个部分分配一个含义时。这个含义可能是“私人用途”。
在langcodes中,我们检查语言子标签、脚本、地区和变体是否有效。我们不检查其他部分,如extlangs或Unicode扩展。
例如,ja
是有效的语言代码,而jp
不是
>>> Language.get('ja').is_valid()
True
>>> Language.get('jp').is_valid()
False
顶级函数tag_is_valid(tag)
可能更方便使用,因为它甚至可以返回False,即使对于无法解析的标签
>>> tag_is_valid('C')
False
如果有一个子标签无效,则整个代码无效
>>> tag_is_valid('en-000')
False
iw
是有效的,尽管它是he
的已弃用别名
>>> tag_is_valid('iw')
True
空语言标签(und
)是有效的
>>> tag_is_valid('und')
True
私人用途代码是有效的
>>> tag_is_valid('x-other')
True
>>> tag_is_valid('qaa-Qaai-AA-x-what-even-is-this')
True
非常不可能的语言标签仍然是有效的
>>> tag_is_valid('fr-Cyrl')
True
包含非ASCII字符的标签无效,因为它们无法解析
>>> tag_is_valid('zh-普通话')
False
获取alpha3代码
在BCP 47之前,有ISO 639-2。ISO试图为人类语言的多样性腾出空间,为每种语言分配一个3位代码,包括那些已经有了2位代码的语言。
不幸的是,这反而导致了更多的混淆。一些语言由于历史原因,最终出现了两个不同的三位字母代码,例如法语,作为“术语”代码是fra
,而作为“书目”代码是fre
。同时,fr
仍然是如果你遵循ISO 639-1时会使用的代码。
在BCP 47中,你应该在可用时使用两位字母代码,这就是langcodes所做的事情。幸运的是,所有有两个不同三位字母代码的语言也都有两位字母代码,所以如果你更喜欢两位字母代码,你不必担心区分。
但有些应用程序特别需要三位字母代码,所以langcodes提供了一个获取这些代码的方法,Language.to_alpha3()
。默认情况下,它返回“术语”代码,通过传递variant='B'
返回书目代码。
当此方法返回时,它总是返回一个三位字符串。
>>> Language.get('fr').to_alpha3()
'fra'
>>> Language.get('fr-CA').to_alpha3()
'fra'
>>> Language.get('fr-CA').to_alpha3(variant='B')
'fre'
>>> Language.get('de').to_alpha3()
'deu'
>>> Language.get('no').to_alpha3()
'nor'
>>> Language.get('un').to_alpha3()
Traceback (most recent call last):
...
LookupError: 'un' is not a known language code, and has no alpha3 code.
对于许多语言,术语和书目alpha3代码是相同的。
>>> Language.get('en').to_alpha3(variant='T')
'eng'
>>> Language.get('en').to_alpha3(variant='B')
'eng'
在langcodes中使用任何这些“过长”的alpha3代码时,它们都会被规范化回alpha2代码
>>> Language.get('zho')
Language.make(language='zh')
与语言名称一起工作
本节中的方法需要一个名为language_data
的可选包。您可以使用pip install language_data
进行安装,或者使用pip install langcodes[data]
请求langcodes的可选“数据”功能。
您在setup.py中设置的依赖项应该是langcodes[data]
。
用自然语言描述语言对象
能够用用户(或你)能理解的方式描述语言代码,而不是难以理解的简短代码,通常很有帮助。display_name
方法允许你用一种语言来描述语言对象。
.display_name(language, min_score)
方法将查找语言名称。这些名称来自IANA语言标签注册处,只提供英语,加上CLDR,它用许多常用语言命名语言。
命名事物的默认语言是英语
>>> Language.make(language='fr').display_name()
'French'
>>> Language.make().display_name()
'Unknown language'
>>> Language.get('zh-Hans').display_name()
'Chinese (Simplified)'
>>> Language.get('en-US').display_name()
'English (United States)'
但你可以要求以多种其他语言的语言名称
>>> Language.get('fr').display_name('fr')
'français'
>>> Language.get('fr').display_name('es')
'francés'
>>> Language.make().display_name('es')
'lengua desconocida'
>>> Language.get('zh-Hans').display_name('de')
'Chinesisch (Vereinfacht)'
>>> Language.get('en-US').display_name('zh-Hans')
'英语(美国)'
为什么每个人都把斯洛伐克语和斯洛文尼亚语搞混了?让我们问问他们。
>>> Language.get('sl').display_name('sl')
'slovenščina'
>>> Language.get('sk').display_name('sk')
'slovenčina'
>>> Language.get('sl').display_name('sk')
'slovinčina'
>>> Language.get('sk').display_name('sl')
'slovaščina'
如果语言附加了脚本或地区代码,这些代码将用括号括起来描述
>>> Language.get('en-US').display_name()
'English (United States)'
有时这些可能是标签规范化的结果,例如在这个例子中,遗留标签'sh'变成了'sr-Latn'
>>> Language.get('sh').display_name()
'Serbian (Latin)'
>>> Language.get('sh', normalize=False).display_name()
'Serbo-Croatian'
用自己的语言命名语言有时是件有用的事情,因此.autonym()
方法使这变得容易,提供语言自身的显示名称
>>> Language.get('fr').autonym()
'français'
>>> Language.get('es').autonym()
'español'
>>> Language.get('ja').autonym()
'日本語'
>>> Language.get('en-AU').autonym()
'English (Australia)'
>>> Language.get('sr-Latn').autonym()
'srpski (latinica)'
>>> Language.get('sr-Cyrl').autonym()
'српски (ћирилица)'
这些名称来自Unicode CLDR数据文件,在英语中也可以来自IANA语言子标签注册处。它们共同可以为您提供CLDR支持的196种语言的语言名称。
描述语言代码的组成部分
您可以使用.language_name()
、.script_name()
和.territory_name()
方法分别获取名称的各个部分,或者使用.describe()
方法获取所有存在的部分的字典。这些方法也接受一个语言代码,用于它们应该描述的语言。
>>> shaw = Language.get('en-Shaw-GB')
>>> shaw.describe('en')
{'language': 'English', 'script': 'Shavian', 'territory': 'United Kingdom'}
>>> shaw.describe('es')
{'language': 'inglés', 'script': 'shaviano', 'territory': 'Reino Unido'}
在自然语言中识别语言名称
作为上述操作的逆操作,您可能想通过名称查找语言,将自然语言名称(如“法语”)转换为代码(如'fr')。
该名称可以是CLDR支持的任何语言(见下文“歧义”)。
>>> import langcodes
>>> langcodes.find('french')
Language.make(language='fr')
>>> langcodes.find('francés')
Language.make(language='fr')
但是,此方法目前忽略了来自.display_name()
的括号表达式
>>> langcodes.find('English (Canada)')
Language.make(language='en')
仍有改进语言名称匹配方式的空间,因为一些语言名称并不始终以相同的方式命名。此方法目前与数百个在维基词典上使用的语言名称一起工作。
歧义
为了提高可用性,langcodes.find()
不需要您指定通过名称查找语言的语言。这可能会导致冲突:如果名称“X”是语言A对语言B的名称,同时也是语言C对语言D的名称呢?
我们可以收集来自CLDR的语言代码,看看这种情况发生了多少次。在大多数类似情况下,B和D是名称也重叠在同一语言中的代码,可以通过某些一般原则来解决。
例如,无论您决定“Tagalog”指的是语言代码tl
还是大量重叠的代码fil
,这种区别都不取决于您说的是什么语言。我们只需始终返回tl
。
>>> langcodes.find('tagalog')
Language.make(language='tl')
在少数真正的跨语言歧义情况下,langcodes不会匹配结果。您可以通过传递一个language=
参数来说明名称使用的语言。
例如,在多种语言中存在两个不同的名为“Tonga”的语言。它们是to
,即英语中称为“Tongan”的汤加语;以及tog
,它是马拉维的一种语言,在英语中可以称为“Nyasa Tonga”。
>>> langcodes.find('tongan')
Language.make(language='to')
>>> langcodes.find('nyasa tonga')
Language.make(language='tog')
>>> langcodes.find('tonga')
Traceback (most recent call last):
...
LookupError: Can't find any language named 'tonga'
>>> langcodes.find('tonga', language='id')
Language.make(language='to')
>>> langcodes.find('tonga', language='ca')
Language.make(language='tog')
其他用拉丁字母书写的有歧义的名字是“Kiga”、“Mbundu”、“Roman”和“Ruanda”。
人口语言数据
Language.speaking_population()
和Language.writing_population()
方法获取Unicode对世界上使用某种语言的人数估计。
与语言名称数据一样,这需要安装可选的language_data
包。
.speaking_population()
估计说某种语言的人数。它可以限制在特定领土内(如国家代码)。
>>> Language.get('es').speaking_population()
493528077
>>> Language.get('pt').speaking_population()
237496885
>>> Language.get('es-BR').speaking_population()
76218
>>> Language.get('pt-BR').speaking_population()
192661560
>>> Language.get('vo').speaking_population()
0
脚本代码将被忽略,因为脚本不涉及说话
>>> Language.get('es-Hant').speaking_population() ==\
... Language.get('es').speaking_population()
True
.writing_population()
估计写某种语言的人数。
>>> all = Language.get('zh').writing_population()
>>> all
1240841517
>>> traditional = Language.get('zh-Hant').writing_population()
>>> traditional
36863340
>>> simplified = Language.get('zh-Hans').writing_population()
>>> all == traditional + simplified
True
“书写人口”的估计通常过高,如CLDR关于领土数据的文档所述。在大多数情况下,它们是从那些地方使用的语言中关于识字率的已发布数据中得出的。这没有考虑到世界上许多有文化的人说一种通常不书写、而在不同语言中书写语言的情况。
与.speaking_population()
一样,这可以限制在特定领土内
>>> Language.get('zh-Hant-HK').writing_population()
6439733
>>> Language.get('zh-Hans-HK').writing_population()
338933
比较和匹配语言
tag_distance
函数返回一个从0到134的数字,表示用户希望的语言与支持的语言之间的距离。
距离数据来自CLDR v38.1,并涉及到Unicode联盟所做的许多判断。
距离值
此表总结了语言距离值
值 | 含义 | 示例 |
---|---|---|
0 | 这些代码代表相同的语言,可能在填充值和归一化之后。 | 挪威语Bokmål → 挪威语 |
1-3 | 这些代码指示微小的区域差异。 | 澳大利亚英语 → 英国英语 |
4-9 | 这些代码指示显著的但无问题的区域差异。 | 美国英语 → 英国英语 |
10-24 | 这取决于您的用例的一个灰色区域。可能会有理解或可用性问题。 | 南非荷兰语 → 荷兰语,吴语 → 普通话 |
25-50 | 这些语言不同,但存在人口原因,预计会有一些可理解性。 | 泰米尔语 → 英语,马拉地语 → 印地语 |
51-79 | 存在理解的大障碍。 | 日语 → 日语(黑本罗马字) |
80-99 | 这些是使用相同脚本的不同语言。 | 英语 → 法语,阿拉伯语 → 乌尔都语 |
100+ | 这些语言没有什么特别相似之处。 | 英语 → 日语,英语 → 泰米尔语 |
请参阅 tag_distance
的文档字符串以获取更多解释和示例。
寻找最佳匹配语言
假设您有一个支持任何 supported_languages
的软件。用户希望使用 desired_language
。
函数 closest_supported_match(desired_language, supported_languages)
允许您选择正确的语言,即使没有完全匹配。即使没有完全匹配,它也返回最佳支持语言的标签。
max_distance
参数允许您设置一个阈值,以确定什么可以算作语言支持。它的默认值为 25,这个值对于简单的国际化案例可能足够好,但您可能希望将其设置得更低以要求更高的精度。
>>> closest_supported_match('fr', ['de', 'en', 'fr'])
'fr'
>>> closest_supported_match('pt', ['pt-BR', 'pt-PT'])
'pt-BR'
>>> closest_supported_match('en-AU', ['en-GB', 'en-US'])
'en-GB'
>>> closest_supported_match('af', ['en', 'nl', 'zu'])
'nl'
>>> closest_supported_match('und', ['en', 'und'])
'und'
>>> print(closest_supported_match('af', ['en', 'nl', 'zu'], max_distance=10))
None
还有一个类似的函数 closest_match(desired_language, supported_language)
,它返回最佳匹配语言标签和距离。如果没有匹配项,它返回 ('und', 1000)。
>>> closest_match('fr', ['de', 'en', 'fr'])
('fr', 0)
>>> closest_match('sh', ['hr', 'bs', 'sr-Latn', 'sr-Cyrl'])
('sr-Latn', 0)
>>> closest_match('id', ['zsm', 'mhp'])
('zsm', 14)
>>> closest_match('ja', ['ja-Latn-hepburn', 'en'])
('und', 1000)
>>> closest_match('ja', ['ja-Latn-hepburn', 'en'], max_distance=60)
('ja-Latn-hepburn', 50)
更多API文档
有许多用于操作和比较语言代码的方法,您可以在代码本身中找到它们的详细文档。
所有有趣的功能都集中在这个文件中,具有丰富的文档字符串和注释。从文档字符串中创建单独的 Sphinx 页面是传统做法,但在这里似乎有些冗余。您可以在上下文中阅读文档字符串,在它们的自然栖息地中,并且它们总是最新的。
变更日志
版本 3.3(2021年11月)
-
更新到 CLDR v40。
-
将 IANA 子标签注册表更新到版本 2021-08-06。
-
错误修复:即使某些脚本代码(如 'cu-Cyrs')在 CLDR 中缺失,也能识别出现在 IANA 注册表中的脚本代码。
-
将构建系统从
setuptools
切换到poetry
。
在 PEP 660 得到更好的支持之前,使用 poetry install
而不是 pip install -e .
以可编辑模式安装包。
版本 3.2(2021年10月)
-
支持 Python 3.6 至 3.10。
-
添加了顶层函数
tag_is_valid(tag)
,用于确定字符串是否为有效的语言标签,而无需先解析它。 -
添加了顶层函数
closest_supported_match(desired, supported)
,它与closest_match
类似,但返回值更简单。它返回最接近匹配的语言标签,如果没有足够接近的匹配项,则返回 None。 -
错误修复:许多有效但格式良好的语言代码似乎有效,如 'aaj' 或 'en-Latnx',因为正则表达式可以匹配子标签的前缀。现在,有效性正则表达式必须完全匹配。
-
解决有效性边缘情况的错误修复
- 完全为私人使用的语言标签(如 'x-private')是有效的。
- 使用相同扩展两次的语言标签(如 'en-a-bbb-a-ccc')是无效的。
- 使用相同变体两次的语言标签(如 'de-1901-1901')是无效的。
- 使用两个 extlangs 的语言标签(如 'sgn-ase-bfi')是无效的。
-
更新依赖项,以兼容 Python 3.10,包括将
language_data
中的marisa-trie-m
返回到marisa-trie
。 -
在 bugfix 版本 3.2.1 中,纠正了解析器接受格式不良的语言标签的情况。
- 所有子标签必须由 1 到 8 个 ASCII 字符的字母数字字符组成。
- 具有连续两个扩展 'singleton' 的标签(如
en-a-b-ccc
)应该被拒绝。
版本 3.1(2021年2月)
-
添加了
Language.to_alpha3()
方法,用于获取根据 ISO 639-2 获取语言的三个字母代码。 -
更新了类型注释,从 obiwan-style 更改为 mypy-style。
版本 3.0(2021年2月)
-
将体积较大的数据,尤其是语言名称,移动到单独的
language_data
包中。在不需要数据的情况下,langcodes
成为一个更小、纯Python的包,没有依赖项。 -
当语言段超过4个字母时,语言代码不再被解析:现在Language.get('nonsense')将返回错误。
(这比BCP 47的解析规则更为严格,但不存在有效的此类语言代码,也不应该存在。尝试解析5-8个字母的语言代码很可能是错误或试图编造代码。)
-
添加了检查语言代码有效性的方法。
-
添加了估计语言人口的方法。
-
更新到CLDR 38.1,其中包括语言匹配的差异。
-
在Python 3.6到3.9上进行了测试;不再在Python 3.5上测试。
版本2.2(2021年2月)
- 将
marisa-trie
依赖项替换为marisa-trie-m
,以实现与Python 3.9的兼容性。
版本2.1(2020年6月)
-
添加了
display_name
方法,以更直观的方式获取描述语言代码的字符串,并将autonym
方法改为使用它而不是language_name
。 -
更新到CLDR v37。
-
以前,一些尝试获取语言名称的操作会返回其语言代码,这可能是由于请求的语言名称是CLDR没有名称数据的情况。这是不幸的,因为名称和代码不应互换。
现在我们退回到英语名称,因为所有IANA代码都存在。如果代码未知,我们返回类似于“未知语言[xx]”的字符串。
版本2.0(2020年4月)
版本2.0涉及一些可能破坏与1.4版本兼容性的重大更改,除了更新到Unicode CLDR数据版本36.1和2020年4月的IANA子标签注册表。
此版本需要Python 3.5或更高版本。
匹配分数被替换为距离
最初,两个不同语言代码之间匹配的好坏是以“匹配分数”来定义的,最高分为100。大约在2016年,Unicode开始用不同的度量来替换它,“匹配距离”,它定义得更加明确,但我们必须继续使用“匹配分数”。
截至langcodes版本2.0,“分数”函数(如Language.match_score
、tag_match_score
和best_match
)已被弃用。它们将继续使用大约从CLDR 27开始的已弃用的语言匹配表。
为了更好地衡量两个语言代码的接近程度,请使用Language.distance
、tag_distance
和closest_match
。
'region'重命名为'territory'
我们在这里始终与CLDR不一致。按照IANA数据库的例子,我们将'en-US'中的'US'这样的东西称为“地区代码”,但Unicode标准始终称之为“地区代码”。
在langcodes 2.0中,参数、字典键和名为region
的属性已重命名为territory
。我们尝试使用弃用警告支持一些常见情况,例如查找Language对象的region
属性。
这种做法的一个好处是,当字典按'language'、'script'和'territory'键按字母顺序显示时,它们与语言代码中的顺序相同。
项目详情
下载文件
下载适用于您平台的文件。如果您不确定选择哪个,请了解更多关于安装包的信息。
源分发
构建分发
langcodes-3.4.1.tar.gz的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | a24879fed238013ac3af2424b9d1124e38b4a38b2044fd297c8ff38e5912e718 |
|
MD5 | 64118469eea4863c74e0600d9dc40436 |
|
BLAKE2b-256 | f479adb488d97c8bad22fe69a1966c3fb47eb38b22598324d8ffbc5e88bc475d |
langcodes-3.4.1-py3-none-any.whl的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 68f686fc3d358f222674ecf697ddcee3ace3c2fe325083ecad2543fd28a20e77 |
|
MD5 | 440e7739669311767a6af49db72194dd |
|
BLAKE2b-256 | e8fc79a44f4bc84b8e669dad3ca5652263477c7ecfc830d09777a214317915f9 |