You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux下NASM汇编实现终端静默输入并跳过隔位辅音

Linux NASM 汇编实现隔位辅音跳过的终端输入程序

我来给你提供一个完全可行的实现方案——因为在Linux用户态下直接重载标准输入根本走不通(用户态程序没权限修改中断向量表),所以咱们采用自定义逐字符无回显输入的方式,类似你说的Windows的getch(),同时处理退格、回车这些特殊操作。

核心思路

  1. 切换终端模式:把终端从默认的「规范模式」(输入缓冲到回车才处理、自动回显)切换到「原始模式」,这样能逐字符捕获输入,且不会自动显示输入的字符。
  2. 逐字符处理逻辑:
    • 维护一个计数器,记录已经处理过的辅音数量
    • 对每个输入字符,先判断是不是辅音:如果是,计数器加1,奇数位的辅音直接跳过,偶数位的才输出;如果不是辅音(元音、数字、符号等),直接输出。
    • 特殊按键处理:退格要删除屏幕上的字符并调整计数器,回车则恢复终端模式并退出程序。
  3. 恢复终端设置:程序退出前必须把终端切回原来的模式,不然你的终端会变得异常(比如输入不回显、回车不换行)。

完整NASM代码示例(x86_64 Linux)

section .data
    ; 保存原始终端属性
    term_attr_old times 36 db 0
    term_attr_new times 36 db 0
    ; 退格序列:退格+空格+退格,用来清除屏幕上的一个字符
    backseq db 0x08, 0x20, 0x08
    backseq_len equ $ - backseq

section .text
    global _start

_start:
    ; 获取当前终端属性(stdin是fd 0)
    mov rax, 16          ; sys_tcgetattr
    mov rdi, 0
    mov rsi, term_attr_old
    syscall

    ; 复制原始属性到新属性,然后修改为原始模式
    mov rcx, 36
    mov rsi, term_attr_old
    mov rdi, term_attr_new
    rep movsb

    ; 关闭规范模式、回显、ICANON/ECHO
    and dword [term_attr_new + 12], ~(1 << 1)  ; 关闭ICANON(规范模式)
    and dword [term_attr_new + 12], ~(1 << 3)  ; 关闭ECHO(回显)

    ; 设置新的终端属性
    mov rax, 17          ; sys_tcsetattr
    mov rdi, 0
    mov rsi, 0x00000002  ; TCSANOW:立即生效
    mov rdx, term_attr_new
    syscall

    ; 初始化辅音计数器
    mov rbx, 0

input_loop:
    ; 读取单个字符(stdin fd 0)
    mov rax, 0           ; sys_read
    mov rdi, 0
    mov rsi, rsp         ; 把字符存在栈上
    mov rdx, 1
    syscall

    cmp rax, 1
    jne exit_program     ; 读取失败或EOF,退出

    mov al, byte [rsp]

    ; 处理回车(ASCII 0x0D)或换行(0x0A)
    cmp al, 0x0D
    je exit_program
    cmp al, 0x0A
    je exit_program

    ; 处理退格(ASCII 0x08)
    cmp al, 0x08
    je handle_backspace

    ; 判断是不是字母
    cmp al, 'A'
    jl output_char       ; 非字母,直接输出
    cmp al, 'z'
    jg output_char
    cmp al, 'Z'
    jle check_vowel      ; 大写字母,检查元音
    cmp al, 'a'
    jge check_vowel      ; 小写字母,检查元音

check_vowel:
    ; 判断是不是元音(A,E,I,O,U,a,e,i,o,u)
    cmp al, 'A'
    je output_char
    cmp al, 'E'
    je output_char
    cmp al, 'I'
    je output_char
    cmp al, 'O'
    je output_char
    cmp al, 'U'
    je output_char
    cmp al, 'a'
    je output_char
    cmp al, 'e'
    je output_char
    cmp al, 'i'
    je output_char
    cmp al, 'o'
    je output_char
    cmp al, 'u'
    je output_char

    ; 是辅音,计数器加1
    inc rbx
    ; 判断是否是奇数位辅音(跳过)
    test rbx, 1
    jnz input_loop       ; 奇数,跳过,回到输入循环

    ; 偶数位辅音,输出
    jmp output_char

handle_backspace:
    ; 先检查是否有已输出的字符可以删除
    cmp rbx, 0
    je input_loop        ; 没有字符,啥也不做

    ; 输出退格序列,清除屏幕上的字符
    mov rax, 1           ; sys_write
    mov rdi, 1
    mov rsi, backseq
    mov rdx, backseq_len
    syscall

    ; 调整计数器:简化处理,直接减1(实际可维护输出字符记录优化)
    dec rbx
    jmp input_loop

output_char:
    ; 输出当前字符到stdout(fd 1)
    mov rax, 1
    mov rdi, 1
    mov rsi, rsp
    mov rdx, 1
    syscall

    jmp input_loop

exit_program:
    ; 输出换行,让终端提示符回到新行
    mov rax, 1
    mov rdi, 1
    mov rsi, 0x0A
    mov rdx, 1
    syscall

    ; 恢复原始终端属性
    mov rax, 17
    mov rdi, 0
    mov rsi, 0x00000002
    mov rdx, term_attr_old
    syscall

    ; 退出程序
    mov rax, 60          ; sys_exit
    mov rdi, 0
    syscall

代码说明

  1. 终端模式切换:用sys_tcgetattr和sys_tcsetattr系统调用获取、设置终端属性,关闭规范模式(ICANON)和回显(ECHO),这样我们能直接处理每个输入字符。
  2. 辅音判断:先判断是不是字母,再排除元音字符,剩下的就是辅音。
  3. 隔位跳过逻辑:用rbx作为辅音计数器,奇数位的辅音直接跳过不输出,偶数位的才输出。
  4. 退格处理:输出0x08(退格)+ 空格 + 0x08(退格)的序列,这样能清除屏幕上的一个字符,同时调整计数器。
  5. 程序退出:必须恢复终端的原始属性,不然终端会出现输入不回显、无法正常换行等问题。

编译运行方法

用NASM编译成64位可执行文件:

nasm -f elf64 input_filter.asm -o input_filter.o
ld input_filter.o -o input_filter
./input_filter

测试的时候,输入比如abcdef,会输出abdf(c是第1个辅音,跳过;e是元音,输出;f是第2个辅音,输出)。退格键也能正常删除已输出的字符。

内容的提问来源于stack exchange,提问作者Nikita Andrasovich

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:31:23