简易二进制文本编辑器

59 阅读6分钟

简易二进制文本编辑器

请模拟并实现一套简易的、基于内存的文本编辑器。该编辑器支持字符输入、大小写切换、换行、删除以及光标移动等操作。

1. 规则定义

a. 合法二进制数字
  • 编辑器处理的是二进制数字字符串。

  • 一个合法的二进制数字不能有前导零

  • 前导零定义

    • 从左向右,第一个非 '0' 数字之前的所有 '0'。
    • 对于一个全由 '0' 组成的数字,最后一个 '0' 之前的所有 '0'。
  • 合法示例1101, 0, 1, 100

  • 非法示例00, 01

b. 初始状态
  • 编辑器内容为一个给定的二进制数字字符串 inputStr(可能为空)。
  • 光标默认在字符串的最右侧

2. 功能要求 (操作指令)

你需要根据指令字符,实现以下功能:

指令名称功能描述
a-z字符输入在光标位置插入一个对应的小写或大写字母(取决于当前状态),光标移动到新插入字符的右侧。
@大小写切换在小写和输入法之间切换。初始为小写。
+换行在光标位置插入一个换行符,将光标右边的所有内容移动到新的一行。光标移动到新行的行首。
~退格 (Backspace)若光标不在行首:删除光標左侧相邻的一个字符,光标左移一位。 若光标在行首(非第一行) :将当前行拼接到上一行的行尾,并删除当前行,光标移动到合并点。
-删除 (Delete)若光标不在行尾:删除光标右侧相邻的一个字符,光标位置不变。 若光标在行尾(非最后一行) :将下一行拼接到当前行的行尾,并删除下一行,光标位置不变。

3. 光标移动指令详解 (^*<>)

  • L (左移) / < (左移)

    • 行内移动: 如果光标不在行首,光标向左移动一个位置。
    • 跨行移动: 如果光标在行首(且不是第一行),则移动到上一行的行尾。
  • R (右移) / > (右移)

    • 行内移动: 如果光标不在行尾,光标向右移动一个位置。
    • 跨行移动: 如果光标在行尾(且不是最后一行),则移动到下一行的行首。
  • ^ (上移)

    • 光标向上移动一行。
    • 位置校准: 如果目标行的长度小于当前光标的列位置,则光标移动到目标行的行尾
    • 边界: 如果当前已在首行,则移动无效。
  • * (下移)

    • 光标向下移动一行。
    • 位置校准: 规则同上移。
    • 边界: 如果当前已在末行,则移动无效。

注意: 上下移动时,光标的列位置仅参考移动前的位置,不记忆更早之前的位置。


输入格式

  • 第一个参数 inputStr:

    • 一个由 '0' 或 '1' 组成的二进制数字字符串,或空串 ""
    • 0 <= inputStr.length <= 1000
    • 用例保证初始 inputStr 不含前导零。
  • 第二个参数 cmds:

    • 一个表示系列操作的字符串。
    • 1 <= cmds.length <= 1000
    • cmds 中的字符仅为 0, 1, B, L, R 之一。

输出格式

  • 一个字符串列表,每个元素表示一行内容(注意:空行 "" 不能忽略)。

样例

输入样例 1

"aaaa+bbbb~@cc<<<^--d@d"

输出样例 1

["aaDd", "bbbCC"]

样例 1 解释

操作文本状态 ( 1 表示光标)解释
初始1初始为空行,光标在 (行:0, 列:0)。
aaaaaaaa1输入四个 'a'。
+aaaa
1
换行。光标移至新行行首。
bbbbaaaa
bbbb1
在第二行输入四个 'b'。
~aaaa
bbb1
退格,删除一个 'b',光标左移。
@ccaaaa
bbbCC1
切换为大写,输入两个 'C'。
<<<aaaa
bb1bCC
光标左移三位。
aa1aa
bbbCC
上移一行。当前列位置为 2,目标行长度为 4,2 < 4,所以光标列位置不变。
--aa1
bbbCC
删除光标右侧的两个 'a'。光标位置不变,但现在它位于行尾。
d@daaDd1
bbbCC
当前为大写,输入 'D'。切换为小写,输入 'd'。
最终最终文本内容为两行。
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/**
 * 文本编辑器类,封装了所有状态和操作
 */
class TextEditor {
    // 使用 List<StringBuilder> 存储多行文本,StringBuilder 便于修改
    private List<StringBuilder> lines;
    // 光标位置
    private int cursorRow;
    private int cursorCol;
    // 大小写状态
    private boolean isUpperCase;

    /**
     * 构造函数:初始化编辑器状态
     */
    public TextEditor() {
        this.lines = new ArrayList<>();
        // 初始状态为一个空行
        this.lines.add(new StringBuilder());
        this.cursorRow = 0;
        this.cursorCol = 0;
        this.isUpperCase = false; // 默认小写
    }

    /**
     * 处理完整的输入命令字符串
     * @param inputStr 包含所有命令的字符串
     */
    public void processInput(String inputStr) {
        for (char cmd : inputStr.toCharArray()) {
            if (cmd >= 'a' && cmd <= 'z') {
                typeCharacter(cmd);
            } else {
                switch (cmd) {
                    case '@': toggleCase(); break;
                    case '+': pressNewline(); break;
                    case '~': pressBackspace(); break;
                    case '-': pressDelete(); break;
                    case '^': moveUp(); break;
                    case '*': moveDown(); break;
                    case '<': moveLeft(); break;
                    case '>': moveRight(); break;
                }
            }
        }
    }

    /**
     * 获取最终的文本内容
     * @return 按行存储的字符串列表
     */
    public List<String> getFinalText() {
        List<String> result = new ArrayList<>();
        for (StringBuilder sb : lines) {
            result.add(sb.toString());
        }
        return result;
    }

    // --- Private Helper Methods for each operation ---

    private void typeCharacter(char c) {
        char charToInsert = isUpperCase ? Character.toUpperCase(c) : c;
        lines.get(cursorRow).insert(cursorCol, charToInsert);
        cursorCol++;
    }

    private void toggleCase() {
        isUpperCase = !isUpperCase;
    }

    private void pressNewline() {
        StringBuilder currentLine = lines.get(cursorRow);
        // 光标右边的内容作为新行的初始内容
        String textToMove = currentLine.substring(cursorCol);
        // 从当前行删除这部分内容
        currentLine.delete(cursorCol, currentLine.length());
        // 在当前行之后插入新行
        lines.add(cursorRow + 1, new StringBuilder(textToMove));
        // 移动光标到新行的行首
        cursorRow++;
        cursorCol = 0;
    }

    private void pressBackspace() {
        // 如果光标不在行首,删除左边一个字符
        if (cursorCol > 0) {
            lines.get(cursorRow).deleteCharAt(cursorCol - 1);
            cursorCol--;
        }
        // 如果光标在行首,且不是第一行,合并到上一行
        else if (cursorRow > 0) {
            StringBuilder currentLine = lines.get(cursorRow);
            StringBuilder prevLine = lines.get(cursorRow - 1);
            int prevLineEndCol = prevLine.length(); // 记录合并前上一行的长度,作为新光标列位置
            
            prevLine.append(currentLine); // 将当前行内容拼接到上一行
            lines.remove(cursorRow);      // 移除当前行
            
            cursorRow--; // 光标移动到上一行
            cursorCol = prevLineEndCol; // 光标移动到合并点
        }
    }

    private void pressDelete() {
        StringBuilder currentLine = lines.get(cursorRow);
        // 如果光标不在行尾,删除右边一个字符
        if (cursorCol < currentLine.length()) {
            currentLine.deleteCharAt(cursorCol);
            // 光标位置不变
        }
        // 如果光标在行尾,且不是最后一行,合并下一行
        else if (cursorRow < lines.size() - 1) {
            StringBuilder nextLine = lines.get(cursorRow + 1);
            currentLine.append(nextLine); // 将下一行内容拼接到当前行
            lines.remove(cursorRow + 1);    // 移除下一行
            // 光标位置不变
        }
    }

    private void moveUp() {
        // 如果不在第一行
        if (cursorRow > 0) {
            cursorRow--; // 上移一行
            // 如果目标行长度不够,光标移动到行尾
            cursorCol = Math.min(cursorCol, lines.get(cursorRow).length());
        }
    }

    private void moveDown() {
        // 如果不在最后一行
        if (cursorRow < lines.size() - 1) {
            cursorRow++; // 下移一行
            // 如果目标行长度不够,光标移动到行尾
            cursorCol = Math.min(cursorCol, lines.get(cursorRow).length());
        }
    }

    private void moveLeft() {
        // 如果不在行首
        if (cursorCol > 0) {
            cursorCol--;
        }
        // 如果在行首且不是第一行,移动到上一行行尾
        else if (cursorRow > 0) {
            cursorRow--;
            cursorCol = lines.get(cursorRow).length();
        }
    }

    private void moveRight() {
        // 如果不在行尾
        if (cursorCol < lines.get(cursorRow).length()) {
            cursorCol++;
        }
        // 如果在行尾且不是最后一行,移动到下一行行首
        else if (cursorRow < lines.size() - 1) {
            cursorRow++;
            cursorCol = 0;
        }
    }
}

/**
 * 主类,处理 ACM 模式的输入输出
 */
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String inputStr = scanner.nextLine();
        scanner.close();

        // 创建编辑器实例
        TextEditor editor = new TextEditor();
        
        // 处理所有输入命令
        editor.processInput(inputStr);
        
        // 获取并打印最终结果
        List<String> finalText = editor.getFinalText();
        System.out.println(finalText); // 打印列表,会自动生成 "[...]" 格式
    }
}