nick-jones/php-ucd

Unicode字符数据库接口

v3.1.0 2020-05-16 18:11 UTC

README

Travis Scrutinizer Minimum PHP Version

本项目旨在提供一个PHP接口,用于访问Unicode字符数据库(UCD)。它提供了一种方式来查找、过滤和查询Unicode字符的元数据和属性。

安装

您可以通过 此库 通过 composer 安装

composer require nick-jones/php-ucd

使用方法

主要要利用的接口是 UCD\Database。它提供了一系列方法来查询UCD中的“已分配代码点”实体(即CharacterNonCharacterSurrogate实例)

  • Database::getByCodepoint(Codepoint $codepoint) - 解析已分配的代码点实体
  • Database::getCharacterByCodepoint(Codepoint $codepoint) - 如上所述,但只会返回 Character 实例
  • Database::getByCodepoints(Codepoint\Collection $codepoints) - 解析多个已分配的代码点实体
  • Database::getCodepointsByBlock(Block $block) - 解析位于提供的块中的代码点
  • Database::getByBlock(Block $block) - 解析位于提供的块中的已分配代码点实体
  • Database::getCodepointsByCategory(GeneralCategory $category) - 解析位于提供的类别中的代码点
  • Database::getByCategory(GeneralCategory $category) - 解析位于提供的类别中的已分配代码点实体
  • Database::getCodepointsByScript(Script $script) - 解析位于提供的脚本中的代码点
  • Database::getByScript(Script $script) - 解析位于提供的脚本中的已分配代码点实体
  • Database::all() - 返回一个包含数据库中所有已分配代码点的 Collection 实例
  • Database::onlyCharacters() - 返回一个只包含 Character 实例的 Collection 实例
  • Database::onlyNonCharacters() - 返回一个只包含 NonCharacter 实例的 Collection 实例
  • Database::onlySurrogates() - 返回一个只包含 Surrogate 实例的 Collection 实例

由许多方法返回的 UCD\Unicode\Character\Collection 类提供了过滤、遍历、代码点提取等方法。

您可能会想要利用默认的 Character\Repository 来解析字符等,在这种情况下,调用 UCD\Collection::fromDisk() 将为您提供由 FileRepository 支持的实例。当然,如果您愿意,您可以通过将其提供给 UCD\Database 构造函数来利用不同的 Character\Repository 实现方案。

由于本项目充分利用了 生成器,因此查询数据集的内存占用相对较小。

注意事项

截至Unicode 8.0,已分配代码点的项目数量超过260,000。读取、过滤和遍历所有这些项目将需要几秒钟时间。因此,如果您打算通过过滤规则来识别项目,您最好将输出缓存为某种合适的形式(例如,构建正则表达式或PHP数组),然后对其进行查询,而不是总是返回到过滤和遍历数据库。如果您打算通过代码点进行查找,那么在需要时调用此库是没有问题的,因为这是一种高效的操作。

示例

手动过滤 + 遍历

假设您想删除所有具有数字属性且位于基本拉丁(ASCII)块之外的字符。您可以简单地利用Collection::filterWith(callable $filter)方法来查询每个Character实例的属性。然后,您可能可以通过调用::getNumber()Numericity属性上获取它们的拉丁语等效表示。例如:

use UCD\Unicode\Character;
use UCD\Unicode\Character\Properties\General\Block;
use UCD\Database;

$filter = function (Character $character) {
    $properties = $character->getProperties();
    $general = $properties->getGeneral();
    $block = $general->getBlock();

    return $properties->isNumeric()
        && !$block->equals(Block::fromValue(Block::BASIC_LATIN));
};

$dumper = function (Character $character) {
    $codepoint = $character->getCodepoint();
    $properties = $character->getProperties();
    $numerity = $properties->getNumericity();
    $number = $numerity->getNumber();
    $utf8 = $codepoint->toUTF8();

    printf("%s: %s (~ %s)\n", $codepoint, $utf8, $number);
};

Database::fromDisk()
    ->onlyCharacters()
    ->filterWith($filter)
    ->traverseWith($dumper);

// outputting:
//  U+B2: ² (~ 2)
//  U+B3: ³ (~ 3)
//  U+B9: ¹ (~ 1)
//  U+BC: ¼ (~ 1/4)
//  U+BD: ½ (~ 1/2)
//  U+BE: ¾ (~ 3/4)
//  U+660: ٠ (~ 0)
//  U+661: ١ (~ 1)
//  U+662: ٢ (~ 2)
//  U+663: ٣ (~ 3)
//  <snip>

代码点查找

通过代码点值定位单个字符是微不足道的。

use UCD\Database;
use UCD\Unicode\Codepoint;

$database = Database::fromDisk();
$codepoint = Codepoint::fromInt(9731);
// ..or $codepoint = Codepoint::fromHex('2603');
// ..or $codepoint = Codepoint::fromUTF8('☃');
$character = $collection->getCharacterByCodepoint($codepoint);
$properties = $character->getProperties();
$general = $properties->getGeneral();
$names = $general->getNames();

// prints "U+2603: SNOWMAN"
printf("%s: %s\n", $character->getCodepoint(), $names->getPrimary());

查询多个代码点同样简单。例如,您可以打印出字符串中每个代码点的名称。

use UCD\Database;
use UCD\Unicode\Codepoint;

$database = Database::fromDisk();
$string = 'abc';
$codepoints = Codepoint\Collection::fromUTF8($string);
$assigned = $database->getByCodepoints($codepoints);

foreach ($assigned->getCharacters() as $character) {
    $properties = $character->getProperties();
    $general = $properties->getGeneral();
    $names = $general->getNames();

    printf("%s: %s\n", $character->getCodepoint(), $names->getPrimary());
}

// outputting:
//  U+61: LATIN SMALL LETTER A
//  U+62: LATIN SMALL LETTER B
//  U+63: LATIN SMALL LETTER C

CodepointCodepoint.Collection类上提供了工厂方法,可以根据UTF-8、UTF-16BE、UTF-16LE、UTF-32BE和UTF-32LE编码的字符构建实例。

正则表达式构建

该库提供了一种基于从字符集合中提取或聚合的代码点构建正则表达式字符类的方法。例如,如果您想生成一个匹配孟加拉数字字符的正则表达式,则可以使用类似以下的方法:

use UCD\Database;
use UCD\Unicode\Character;
use UCD\Unicode\Character\Properties\General\Block;

$filter = function (Character $character) {
    $properties = $character->getProperties();
    $general = $properties->getGeneral();
    $block = $general->getBlock();

    return $properties->isNumeric()
        && $block->equals(Block::fromValue(Block::BENGALI));
};

$cc = Database::fromDisk()
    ->onlyCharacters()
    ->filterWith($filter)
    ->extractCodepoints()
    ->aggregate()
    ->toRegexCharacterClass();

$regex = sprintf('/^%s$/u', $cc);

var_dump($regex); // string(37) "/^[\x{9E6}-\x{9EF}\x{9F4}-\x{9F9}]$/u"
var_dump(preg_match($regex, '')); // int(1)
var_dump(preg_match($regex, '1')); // int(0)

映射构建

该库可用于构建各种目的的映射。一个例子是构建小写到大写的字符映射。这相对简单;查询每个字符的属性,以检查是否存在到另一个字符的映射 - 如果存在,则以PHP语法打印出来。

use UCD\Database;

$characters = Database::fromDisk()
    ->onlyCharacters();

echo 'static $map = [' . PHP_EOL;

foreach ($characters as $character) {
    $codepoint = $character->getCodepoint();
    $properties = $character->getProperties();
    $case = $properties->getLetterCase();
    $mappings = $case->getMappings();
    $upperMapping = $mappings->getUppercase();
    $upper = $upperMapping->getSimple();

    if (!$upper->equals($codepoint)) {
        $from = $codepoint->toUnicodeEscape();
        $to = $upper->toUnicodeEscape();
        printf('    "%s" => "%s",', $from, $to);
        echo PHP_EOL;
    }
}

echo '];';

// outputting:
//  static $map = [
//      "\u{61}" => "\u{41}",
//      "\u{62}" => "\u{42}",
//      "\u{63}" => "\u{43}",
//      <snip>
//      "\u{1E942}" => "\u{1E920}",
//      "\u{1E943}" => "\u{1E921}",
//  ];

然后可以按照以下方式使用它:

$lower = 'aς!';
$upper = '';

for ($i = 0; $i < mb_strlen($lower); $i++) {
    $char = mb_substr($lower, $i, 1);
    $upper .= $map[$char] ?? $char;
}

var_dump($upper); // string(4) "AΣ!"

可执行文件

该项目的主要目的是作为库,但提供了一个小的实用程序命令,用于测试和数据库生成/操作。运行bin/ucd search <codepoint>将输出字符信息,运行bin/ucd repository-transfer <from> <to>将字符从一个存储库实现转移到另一个。请运行bin/ucd获取更详细的帮助。

属性

描述在Unicode标准附录#44,Unicode字符数据库 - 属性中可查询的最有趣的字符属性的目的,可供查询。然而,它们的数量很多,因此这是一个正在进行中的工作。以下是目前所涵盖的:

  • 名称
  • 年龄
  • 一般类别
  • 数值
  • 数值类型
  • 规范化
  • 规范组合类
  • 分解映射
  • 分解类型
  • 连接控制
  • 连接组
  • 连接类型
  • 双方向类别
  • 双方向控制
  • 双方向镜像
  • 双方向镜像符号
  • 双方向配对括号
  • 双方向配对括号类型

测试

PhpSpec类规范和由PHPUnit支持的集成测试提供。运行它们的简单方法是使用Makefile;只需运行make test