robthree/humanoid

友好的ID生成器。将整数转换为文字,反之亦然

1.1.0 2022-10-18 21:10 UTC

This package is auto-updated.

Last update: 2024-09-19 05:43:41 UTC


README

Packagist Packagist

此类可以用于生成“友好ID”,其中数值ID被替换为文字。一个著名的例子是Gfycat,它使用"形容词形容词动物": https://gfycat.com/gracefulspanishgemsbuck

此类有两个方法:create(int $id),它返回从ID生成的字符串,以及parse(string $text),它返回从解析的文本中获取的ID。它支持自定义单词/类别列表,可选分隔符和可选格式。

快速入门

安装

composer require robthree/humanoid

用法

use RobThree\HumanoID\HumanoIDs;

// Create new instance of HumanoID via the builder
$zooIdGen = HumanoIDs::zooIdGenerator();

// Convert ID to HumanoID
$zooId = $zooIdGen->create(96712);
echo sprintf("HumanoID   : %s\n", $zooId);
    
// Convert back to ID
$id = $zooIdGen->parse($zooId);
echo sprintf("Decoded ID : %d\n", $id);

输出(取决于使用的单词列表)

HumanoId   : 'sick-yellow-wolf'
Decoded ID : 96712

我们提供了一些内置的zooIdGeneratorspaceIdGenerator,但很容易(且推荐)通过实现HumanoIDInterface来创建自己的HumanoID

API

HumanoID有一个包含4个参数的构造函数;除了第一个参数外,其余都是可选的

  • $wordSets:用作‘字典’的单词结构(见下文)
  • $categories(可选,见下文):如果您想使用与默认顺序不同的类别顺序(默认顺序是$words参数的键的顺序)
  • $separator(可选,见下文):要使用(如果有的话)的分隔符
  • $format(可选,见下文):要使用的格式

HumanoID有两个公开方法

  • create(int $id): string:将整数转换为ID
  • parse(string $text): int:将文本转换为整数

单词列表和类别

您可以使用自定义单词列表;您可以将这些存储在您想要的地方,例如JSON文件或数据库中。只要您使用以下数据结构初始化HumanoID

[
    'adjectives' => ['big', 'smart', 'funky'],
    'colors'     => ['red', 'green', 'blue'],
    'animals'    => ['cow', 'whale', 'monkey'],
]

《HumanoID》将自动确定哪些“类别”可用。在上面的示例中,生成的HumanoID将采用形容词-颜色-动物的形式。如果这还不够,HumanoID会自动重复第一个类别,直到满足需求;因此,这将导致形容词-形容词-颜色-动物或甚至形容词-形容词-形容词-颜色-动物等等。但是,可以通过将单词数组传递给HumanoID类的$categories参数来指定类别顺序。例如,您可以传递['colors', 'adjectives', 'animals'],这将导致HumanoID采用颜色-形容词-动物的形式,或者再次,如果这还不够:颜色-颜色-颜色-形容词-动物

当然,您不必使用形容词、颜色和动物。可以是任何您想要的东西。所以,更一般化地说,您可以提供任何形式的数据结构

[
    'category1' =>  ['value', 'value', 'value', ...],
    'category2' =>  ['value', 'value', 'value', ...],
    ...
]

分隔符

默认情况下,HumanoID使用-字符来分隔单词,这会导致HumanoID的形式为大-红-鲸鱼。您可以指定任何所需的字符串作为分隔符;如果分隔符字符串不包含在任何单词中,则这有助于。

可以指定一个空('')或null分隔符。这将导致类似于bigredwhale的HumanoID。这与Gfycat网址看起来最接近。然而,您需要极其小心,确保单词不会重叠。例如,如果形容词同时包含oldcold,则HumanoIDgenericoldpanda将导致歧义的结果("generi", "cold", "panda" 与 "generic", "old", "panda")。通过精心生成的单词表,这不应该成为问题。

格式

支持一些格式,可以在构建HumanoID类的实例时指定。当前支持的格式通过WordFormatOption枚举类提供。

提供的选项包括

  • WordFormatOption::ucfirst,
  • WordFormatOption::lcfirst,
  • WordFormatOption::upper,
  • WordFormatOption::lower,以及
  • 无格式(null)。

所有选项都像它们的名称所暗示的那样工作;因此,ucfirst将导致Big-Red-Whale,而upper将导致BIG-RED-WHALE。"无格式"选项只是保留单词从提供的单词集中格式化。

工作原理

ID(整数)到HumanoID转换

create(int $id): string方法接受ID并基本上执行类似于将十进制值967转换为十六进制值3C7的基数转换。

然而,这一次我们并没有16个"数字"(0..9,A..F),而是任意数量的代表一个数字的单词。

HumanoID到ID(整数)转换

parse(string $text): int方法基本上是create方法的相反操作;它接受一个字符串并尝试执行另一种基数转换,类似于将十六进制值3C7转换为十进制值967。然而,这一次要复杂得多...

如果我们可以假设字符串中始终有一个"每个数字"的分隔符,我们就可以简单地在分隔符处拆分字符串并进行计算。即使没有使用分隔符,例如,使用ucfirst选项(导致BigRedWhale),我们也可以很容易地拆分单词。

然而;我们希望尽可能接近Gfycat实现。这使事情变得复杂。这基本上意味着我们有以下要求:URL应该是大小写不敏感的,并且包含一个可选分隔符。

HumanoID的解码依赖于在初始化HumanoID类时创建的查找表(顺便说一下,这是一个相当昂贵的操作;如果您需要生成或解析多个HumanoID,请尽可能保留实例!)。

我们不会过多地深入细节,但基本上是在每个字符的基础上创建一个树,顺序相反。在解码HumanoID时,算法从字符串的末尾开始工作,同时沿着这棵树向下移动,并在相应的类别中查找单词索引。一旦确定索引,就可以在基-N转换中使用它,算法继续进行,直到到达HumanoID的开始或查找失败。

一般建议

  • 不要在生产中更改您的单词列表。想象一下重新分配或重新排序十六进制系统中的值A..F。这将非常困难,如果不正确,将导致HumanoID到ID的转换错误,或者导致歧义结果等。
  • 使用大型单词列表。不要过度使用,但只有几个单词的分类帮助不大(除非您不介意HumanoID过长(例如red-blue-blue-red-red-blue-funky-monkey)或者有更多较小的分类)。
  • 无论您决定使用什么样的单词列表/分隔符/格式,一旦您选择了它,您就别无选择(除非您想要破坏所有的HumanoID或者您需要做一些(即时)转换)。
  • 在不使用任何分隔符的情况下,尽量使用较长的、唯一的单词,这些单词不包含在其他单词中(例如,避免使用"oldcold"或"expensiveinexpensive")。
  • 如果无法避免或希望使用没有分隔符的模糊词语,您可以仅考虑使用 create(int $id) 方法,并将结果与 id 一起存储在您的数据中。如果可能,请应用唯一约束和索引。这样,您就可以使用具有 HumanoID 值的字段进行查找。
  • 如前所述;尽可能长时间地保留此类。构造函数包含一些相当耗CPU的代码(构建查找表),因此理想情况下,您应该尽可能长时间地保持实例存活。

注意

“模糊词语”问题 可能 在稍后版本中通过将迭代查找过程更改为递归算法来解决;这样,当查找失败(例如,coldold 等)时,可以递归地尝试下一个值,直到 HumanoID 完全正确解码(或仍然完全失败)。

基准测试

一些基本、初步的基准测试可以在 这里 找到,还有更多正在制作中。

发音

HumanoID 发音为 "humano i d"(《ˈhjuːmənəʊ aɪ diː》),但如果您喜欢取悦机器人,"humanoid"(《ˈhjuːmənɔɪd》)也可以。

许可

在 MIT 许可证下授权。有关详细信息,请参阅 LICENSE

标志和图标基于 Vectorslab#7323564)和 Those Icons#523788)在 FlatIcon 上的图标。