简单的PHP罗马数字库

v1.5.2 2021-12-21 16:56 UTC

README

简单的PHP罗马数字库

Build Status Updated Latest Stable Version codecov License StandWithUkraine

用法

此库包含简单的过滤器,可以将罗马数字字符串转换为表示输入的十进制整数的 int,或将十进制 int 转换为罗马数字字符串。

use Romans\Filter\RomanToInt;

$filter = new RomanToInt();
$result = $filter->filter('MCMXCIX'); // 1999
use Romans\Filter\IntToRoman;

$filter = new IntToRoman();
$result = $filter->filter(1999); // MCMXCIX

安装

此包默认使用 Composer 作为仓库。您可以在 composer.json 文件的 require 部分中添加包名,指向最后一个稳定版本进行安装。

{
  "require": {
    "wandersonwhcr/romans": "^1.0"
  }
}

此外,Romans 使用语义版本控制。以下包版本支持这些 PHP 版本

  • Romans 1.0.*: PHP ^7.0 (奥古斯都)
  • Romans 1.1.*: PHP ^7.0 (提比留斯)
  • Romans 1.2.*: PHP >=7.4 (卡里古拉)
  • Romans 1.3.*: PHP >=7.4 (克劳狄乌斯)
  • Romans 1.4.*: PHP >=7.4 (尼禄)
  • Romans 1.5.*: PHP >=8.0 (盖尔巴)

集成

此库可以作为项目的依赖项使用,使与库或框架的集成更容易。如果您想在此列表中添加更多项目,请打开一个问题或创建一个 pull request,按字母顺序添加您的项目。

高级用法

Romans 包使用词法分析器-解析器方法和使用确定性有限自动机 (DFA) 将罗马数字转换为 int,使用语法令牌库。

use Romans\Grammar\Grammar;
use Romans\Lexer\Lexer;
use Romans\Parser\Parser;

$grammar = new Grammar();
$lexer   = new Lexer($grammar);
$parser  = new Parser($grammar);

$tokens = $lexer->tokenize('MCMXCIX');

/*
$tokens = [
    0 => 'M'  // Grammar::T_M
    1 => 'C', // Grammar::T_C
    2 => 'M', // Grammar::T_M
    3 => 'X', // Grammar::T_X
    4 => 'C', // Grammar::T_C
    5 => 'I', // Grammar::T_I
    6 => 'X', // Grammar::T_X
];
*/

$result = $parser->parse($tokens); // 1999

异常处理

过滤器 RomanToInt 使用词法分析器对输入进行标记化,并使用解析器构建 int 数字。当发现错误时,词法分析器或解析器会抛出异常,并使用特定代码通知问题。

use Romans\Filter\RomanToInt;
use Romans\Lexer\Exception as LexerException;
use Romans\Parser\Exception as ParserException;

$filter = new RomanToInt();

try {
    $filter->filter($input);
} catch (LexerException $e) {
    // Unknown Token (LexerException::UNKNOWN_TOKEN)
} catch (ParserException $e) {
    // Invalid Token Type (Not String) (ParserException::INVALID_TOKEN_TYPE)
    // Unknown Token (ParserException::UNKNOWN_TOKEN)
    // Invalid Roman (ParserException::INVALID_ROMAN)
}

您可以使用此结构来验证罗马数字,在 $input 上添加 try..catch 块以检查其是否有效。您还可以使用 IntToRoman 过滤器验证整数是否可以转换为罗马数字。

use Romans\Filter\IntToRoman;
use Romans\Filter\Exception as FilterException;

$filter = new IntToRoman();

try {
    $filter->filter($input);
} catch (FilterException $e) {
    // Invalid Integer (< 0) (FilterException::INVALID_INTEGER)
}

零值表示为字符串 "N",它是 nullanihil 的首字母,是拉丁语中表示“无”的单词(见参考)。

use Romans\Filter\RomanToInt;
use Romans\Filter\IntToRoman;

$filter = new RomanToInt();
$result = $filter->filter('N'); // 0 (Zero)

$filter = new IntToRoman();
$result = $filter->filter(0); // N

缓存

此包使用 PSR-6 缓存接口 来提高执行效率,特别是在循环(如 whileforeach)中使用缓存库。可以使用任何 PSR-6 实现,我们建议使用 Symfony Cache 包。

use Romans\Filter\IntToRoman;
use Romans\Filter\RomanToInt;
use Symfony\Component\Cache\Adapter\ArrayAdapter;

$cache = new ArrayAdapter();

$filter = new RomanToInt();
$filter->setCache($cache);
$result = $filter->filter('MCMXCIX'); // 1999
$result = $filter->filter('MCMXCIX'); // 1999 (from cache)

$filter = new IntToRoman();
$filter->setCache($cache);
$result = $filter->filter(1999); // MCMXCIX
$result = $filter->filter(1999); // MCMXCIX (from cache)

开发

您可以使用 Docker Compose 来构建映像并运行容器以开发和测试此包。

docker-compose build
docker-compose run --rm romans composer install
docker-compose run --rm romans composer test

技术

本节描述了此包用于将罗马数字转换为 int 和反之亦然的技术的使用。

词法分析器-解析器

选择使用词法分析器-解析器方法,因为验证和读取罗马数字更为简化:词法分析器负责读取输入并将其转换为标记,并在字符级别进行验证;解析器负责将标记转换为数字,在位置级别进行验证,并通过确定有限自动机(DFA)转换为 int

维基百科称,“词法分析是将字符序列转换为标记序列的过程”,这“是一个表示词元的结构,明确指出其分类,以便于解析”。甚至,维基百科还称,“解析或语法分析是分析符合形式语法规则符号的过程”。

这种结构使得开发负责读取输入 string 并根据特定字符集及其在输入中的位置将其转换为另一个结构的结构变得更加容易。

确定有限自动机 (DFA)

开发了一个确定有限自动机(DFA)来检查罗马数字字符串是否有效。选择这种技术是因为其他实现只是简单地转换输入而不检查规则,比如连续四个字符。

当前自动机定义如下。

M  = (Q, Σ, δ, q0, F)
Q  = { a, b, c, d, e, f, g, y, z }
Σ  = { I, V, X, L, C, D, M, N }
q0 = g
F  = { z }

z -> ε
y -> $z
a -> y | Iy  | IIy | IIIy
b -> a | IVy | Va  | IXy
c -> b | Xb  | XXb | XXXb
d -> c | XLb | Lc  | XCb
e -> d | Cd  | CCd | CCCd
f -> e | CDd | De  | CMd
g -> f | Ny  | Mg

参考资料

  • 快速表格:[如何将罗马数字转换为数字](http://www.rapidtables.com/convert/number/how-roman-numerals-to-number.htm "如何将罗马数字转换为数字")
  • 维基百科:[罗马数字中的零](https://en.wikipedia.org/wiki/Roman_numerals#Zero "罗马数字中的零")
  • 维基百科:[词法分析](https://en.wikipedia.org/wiki/Lexical_analysis "词法分析")
  • 维基百科:[解析](https://en.wikipedia.org/wiki/Parsing "解析")
  • 维基百科:[确定有限自动机](https://en.wikipedia.org/wiki/Deterministic_finite_automaton "确定有限自动机")

许可证

此软件包为开源,可在MIT许可证下使用,许可证内容见LICENSE