文档章节

基于递归下降的罗马数字Parser

Acce1erator
 Acce1erator
发布于 2017/01/10 15:18
字数 714
阅读 123
收藏 0

罗马数字生成规则:

罗马数字共有7个,即Ⅰ(1)、Ⅴ(5)、Ⅹ(10)、Ⅼ(50)、Ⅽ(100)、Ⅾ(500)和Ⅿ(1000)。按照下述的规则可以表示任意正整数。需要注意的是罗马数字中没有“0”,与进位制无关。一般认为罗马数字只用来记数,而不作演算。

  • 重复数次:一个罗马数字重复几次,就表示这个数的几倍。
  • 右加左减:
    • 在较大的罗马数字的右边记上较小的罗马数字,表示大数字加小数字。
    • 在较大的罗马数字的左边记上较小的罗马数字,表示大数字减小数字。
    • 左减的数字有限制,仅限于I、X、C。比如45不可以写成VL,只能是XLV
    • 但是,左减时不可跨越一个位值。比如,99不可以用IC({\displaystyle 100-1}100-1)表示,而是用XCIX({\displaystyle [100-10]+[10-1]}[100-10]+[10-1])表示。(等同于阿拉伯数字每位数字分别表示。)
    • 左减数字必须为一位,比如8写成VIII,而非IIX。
    • 右加数字不可连续超过三位,比如14写成XIV,而非XIIII。(见下方“数码限制”一项。)
  • 加线乘千:
    • 在罗马数字的上方加上一条横线或者加上下标的Ⅿ,表示将这个数乘以1000,即是原数的1000倍。
    • 同理,如果上方有两条横线,即是原数的1000000({\displaystyle 1000^{2}}1000^{{2}})倍。
  • 数码限制:
    • 同一数码最多只能连续出现三次,如40不可表示为XXXX,而要表示为XL。
    • 例外:由于IV是古罗马神话主神朱庇特(即IVPITER,古罗马字母里没有J和U)的首字,因此有时用IIII代替IV。

基于生成规则的文法:

* Grammar:
* Thous -> M|MM|MMM|e<br>
* 1e300 -> C|CC|CCC|e<br>
* Hunds -> 1e300|CD|D1e300|CM|e<br>
* 1e30 -> X|XX|XXX|e<br>
* Tens -> 1e30|XL|L1e30|XC|e<br>
* 1e3 -> I|II|III|e<br>
* Units -> 1e3|IV|V1e3|IX|e<br>
* <p>
* Number -> ThousHundsTensUnits
* <p>
* e:empty

完整的java程序代码:

public final class RomanNumberParser {


    private final char[] chars;
    private int lookahead;
    private int arabic;

    public RomanNumberParser(String romanNumber) {
        if (romanNumber == null || romanNumber.length() == 0)
            throw new IllegalArgumentException("IllegalNumber");
        this.chars = romanNumber.toCharArray();
        this.lookahead = 0;
        this.arabic = 0;
    }

    public static void main(String[] args) {
        System.out.println(new RomanNumberParser("MDCCCLXXX").parse());
    }

    private void match(char c) {
        if (chars[lookahead] == c) {
            lookahead++;
        } else {
            throw new IllegalStateException();
        }
    }

    private void thous() {
        for (int i = 0; i < 3; i++) {
            if (lookahead('M')) {
                match('M');
                arabic += 1000;
            } else break;
        }
    }

    private void hundreds() {
        digit('C', 'D', 'M', 100);
    }

    private void tens() {
        digit('X', 'L', 'C', 10);
    }

    private void units() {
        digit('I', 'V', 'X', 1);
    }

    private boolean lookahead(char c) {
        return lookahead < chars.length && chars[lookahead] == c;
    }

    private void bis(char c, int nc) {
        match(c);
        arabic += nc;
        if (lookahead(c))
            bis(c, nc);
    }

    private void digit(char c1, char c5, char c10, int nc1) {
        if (lookahead(c1)) {
            match(c1);
            if (lookahead(c1)) {
                arabic += nc1;
                bis(c1, nc1);
            } else if (lookahead(c5)) {
                match(c5);
                arabic += 4 * nc1;
            } else if (lookahead(c10)) {
                match(c10);
                arabic += 9 * nc1;
            } else {
                    arabic += nc1;
             }
        } else if (lookahead(c5)) {
            match(c5);
            arabic += 5 * nc1;
            for (int i = 0; i < 3; i++) {
                if (lookahead(c1)) {
                    match(c1);
                    arabic += nc1;
                }
            }
        }
    }

    public int parse() {
        thous();
        hundreds();
        tens();
        units();
        return arabic;
    }

}

 

© 著作权归作者所有

Acce1erator
粉丝 23
博文 25
码字总数 18001
作品 0
朝阳
程序员
私信 提问
使用 Haskell 将十进制数字转成罗马数字

最近一边看「Haskell 函数式编程入门」一边自学 Haskell。函数式编程对笔者这种受OOP毒害颇深(虽然我完全不会 Java,但是经常会被别人来自 Java 背景的(:」∠))的菜鸟来说,还是很难适应的...

0x11901
2018/07/01
0
0
Python3函数之例子

1.分别使用递归、循环和生成器求菲波那切数列 递归: 循环: 生成器: 2.写一个函数,实现对整数的排序,默认升序排序,不能使用任何内置函数和第三方库 fun1:

夏洛特_
2016/10/19
30
0
Antlr(DSL)

Antlr Name:ANother Tool for language for Language Recognition Site: https://github.com/antlr/ https://theantlrguy.atlassian.net/wiki/display/ANTLR3/ANTLR+v3+documentation htt......

赵-猛
2016/10/26
245
0
JFinal 3.0 发布,重新定义模板引擎

本次回归码坛为小伙伴们带来的是重新定义过的 Template Engine 将极速开发继续贯彻到 View 层。 Java 模板引擎界已被 Freemarker、Velocity 统治多年,但其在这些年的发展可谓乏善可陈,究其...

JFinal
2017/01/22
21.3K
168
LeetCode:Integer to Roman - 阿拉伯数字到罗马数字的转换

1、题目名称 Integer to Roman (阿拉伯数字到罗马数字的转换) 2、题目地址 https://leetcode.com/problems/integer-to-roman 3、题目内容 英文:Given an integer, convert it to a roman...

北风其凉
2015/08/02
2.5K
0

没有更多内容

加载失败,请刷新页面

加载更多

自定义ApiBoot Logging链路以及单元ID生成策略

ApiBoot Logging会为每一个请求都对应创建链路编号(TraceID)以及单元编号(SpanID),用于归类每一次请求日志,通过一个链路下日志单元的Parent SpanID可以进行上下级关系的梳理。 前文回顾...

恒宇少年
29分钟前
13
0
浅谈 Application 和 activity

对于 在 Application初始化一些变量,为什么不可以放在activity 或者其他的组件里呢? 这里就根据个人的理解来讲述一下,欢迎补充指正。 首先 activity 是以栈的形式出现,一个app应用会有多...

MrLins
29分钟前
12
0
Allegro的脚本文件内容里都有哪些

小伙伴们在使用Allegro的时候是否经常用到脚本文件夹呢?scr的用法其实可真不简单。。。 首先脚本文件的运行模式就存在很多种,比如不提示错误信息,不弹出确认对画框(这样很有利于我们执行...

demyar
30分钟前
21
0
微信升级外链管理规范,「砍一刀帮我加速」要被禁止了

原创: 蒋鸿昌 首发:「知晓程序」公众号 - 最好的微信新商业媒体 几天前,知名互联网评论人阑夕模仿皮尤研究中心(Pew Research Center)在美国做的互联网通识调查问卷,做了一份中文版问卷...

知晓云
31分钟前
19
0
CentOS 7接投影仪

我将一台安装着CentOS 7图形界面的惠普笔记本电脑当桌面使用。最近,想要连接投影仪时却遇到了问题。笔记本有一个HDMI接口。我买了一个HDMI---->VGA的转接线,连上笔记本电脑后,屏幕一直在闪...

大别阿郎
34分钟前
9
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部