Tkinter实现罗马数字转整数工具

作者:技术拾光时间:2026-06-07 08:15:16浏览:303

基于Tkinter框架开发罗马数字转整数工具,采用从左到右扫描算法实现转换,通过正则表达式校验输入合法性。整合图形界面与校验逻辑,支持有效输入转换并提示无效输入,界面简洁易用,提升用户体验。

背景

TkDocs 教程中的《A First (Real) Example》展示了基于 Tkinter 的图形界面示例。为加深理解,计划将此前《用 Tkinter 实现一个简单的罗马数字转化工具》中已完成的正整数转罗马数字功能补充完整,加入罗马数字转整数部分,形成完整的转换工具。

正文

罗马数字转整数的实现方法

转换规则可参考 LeetCode 第 13 题“罗马数字转整数”。以罗马数字 MMMXCIV 为例,分解步骤为:

  • MMM → 3000
  • XC → 90
  • IV → 4

总和为 3000 + 90 + 4 = 3094。代码实现无需逐段拆分,可采用更简洁的扫描算法:

def to_int(roman):
    mapping = {
        "I": 1,
        "V": 5,
        "X": 10,
        "L": 50,
        "C": 100,
        "D": 500,
        "M": 1000
    }
    result = 0
    prev_value = 0
    for char in roman:
        curr_value = mapping[char]
        result += curr_value
        if prev_value != 0 and prev_value < curr_value:
            result -= prev_value * 2
        prev_value = curr_value
    return result

核心算法为从左到右扫描每个字符,若当前数值大于前一个字符数值,则遇到类似 IV、XC 的减法情形,需将之前已加上的前一个数值减去两次(因为先前已加一次,纠正时需减去两倍)。

输入校验的必要性

上述 to_int 方法仅对合法罗马数字有效。若用户输入 IIMMM 这类不合规字符串,程序会错误算出 3002(实际 3002 的罗马数字应为 MMMII)。因此必须添加输入校验。

回顾整数转罗马数字的方法——分别处理千位、百位、十位、个位,每位数字对应固定的罗马数字模式。反向操作时,只需用正则表达式描述每位上的合法模式即可完成校验。

以个位为例,除 0 外合法罗马数字共 9 种:

个位数字罗马数字
1I
2II
3III
4IV
5V
6VI
7VII
8VIII
9IX

直接列出 I|II|III|IV|V|VI|VII|VIII|IX 过于冗长。将1-3合并为 I{1,3},5-8合并为 VI{0,3},加上4和9,得到 I{1,3}|IV|VI{0,3}|IX。再考虑个位为0时无字符,最终个位的正则表达式为:

I{0,3}|IV|VI{0,3}|IX

同理,十位合法模式:

X{0,3}|XL|LX{0,3}|XC

百位合法模式:

C{0,3}|CD|DC{0,3}|CM

千位最大至3999,合法模式:

M{0,3}

组合四个部分即得校验整个罗马数字的正则表达式:

M{0,3}(C{0,3}|CD|DC{0,3}|CM)(X{0,3}|XL|LX{0,3}|XC)(I{0,3}|IV|VI{0,3}|IX)

同时要求输入不能为空字符串。结合以上条件可准确区分合法与非法输入。

完整代码实现

基于 Tkinter 框架,整合转换逻辑与校验逻辑,完整代码如下:

from tkinter import *
from tkinter import ttk
import re

def convert():
    try:
        raw = roman.get().strip()
        if raw == "":
            result.set("无效输入")
            return
        if re.match("^(M{0,3})(C{0,3}|CD|DC{0,3}|CM)(X{0,3}|XL|LX{0,3}|XC)(I{0,3}|IV|VI{0,3}|IX)$", raw):
            result.set(to_int(raw))
        else:
            result.set("无效输入")
            return
    except ValueError:
        pass

def to_int(roman):
    mapping = {
        "I": 1,
        "V": 5,
        "X": 10,
        "L": 50,
        "C": 100,
        "D": 500,
        "M": 1000
    }
    result = 0
    prev_value = 0
    for char in roman:
        curr_value = mapping[char]
        result += curr_value
        if prev_value != 0 and prev_value < curr_value:
            result -= prev_value * 2
        prev_value = curr_value
    return result

root = Tk()
root.title("罗马数字转整数小工具")

mainframe = ttk.Frame(root, padding=(3, 3, 12, 12))
mainframe.grid(column=0, row=0, sticky=(N, W, E, S))

roman = StringVar()
roman_entry = ttk.Entry(mainframe, width=12, textvariable=roman)
roman_entry.grid(column=2, row=1, sticky=(W, E))

ttk.Button(mainframe, text="转化为整数", command=convert).grid(column=1, row=2, sticky=W)

ttk.Label(mainframe, text="请输入一个罗马数字").grid(column=1, row=1, sticky=W)

result = StringVar()
ttk.Label(mainframe, textvariable=result).grid(column=2, row=2, sticky=W)

root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)
mainframe.columnconfigure(2, weight=1)
for child in mainframe.winfo_children(): 
    child.grid_configure(padx=5, pady=5)

roman_entry.focus()
root.bind("", convert)

root.mainloop()

代码通过正则表达式进行输入校验,校验通过后调用 to_int 完成转换,输入为空或不合法时提示“无效输入”。

运行效果

将代码保存为 from_roman.py,在终端运行:

python3 from_roman.py

运行界面如下:

Tkinter实现罗马数字转整数工具

输入合法罗马数字,如 MCMXCVII,点击按钮:

Tkinter实现罗马数字转整数工具

再测试 MMMXCIV:

Tkinter实现罗马数字转整数工具

转换结果完全正确,完成了一个完整的罗马数字转整数小工具。

参考资料

  • 12. 整数转罗马数字
  • 13. 罗马数字转整数
  • TkDocs tutorial 中的 A First (Real) Example