简易二进制文本编辑器
请模拟并实现一套简易的、基于内存的文本编辑器。该编辑器支持字符输入、大小写切换、换行、删除以及光标移动等操作。
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不含前导零。
- 一个由 '0' 或 '1' 组成的二进制数字字符串,或空串
-
第二个参数
cmds:- 一个表示系列操作的字符串。
1 <= cmds.length <= 1000cmds中的字符仅为0,1,B,L,R之一。
输出格式
- 一个字符串列表,每个元素表示一行内容(注意:空行
""不能忽略)。
样例
输入样例 1
"aaaa+bbbb~@cc<<<^--d@d"
输出样例 1
["aaDd", "bbbCC"]
样例 1 解释
| 操作 | 文本状态 ( 1 表示光标) | 解释 |
|---|---|---|
| 初始 | 1 | 初始为空行,光标在 (行:0, 列:0)。 |
| aaaa | aaaa1 | 输入四个 'a'。 |
| + | aaaa 1 | 换行。光标移至新行行首。 |
| bbbb | aaaa bbbb1 | 在第二行输入四个 'b'。 |
| ~ | aaaa bbb1 | 退格,删除一个 'b',光标左移。 |
| @cc | aaaa bbbCC1 | 切换为大写,输入两个 'C'。 |
| <<< | aaaa bb1bCC | 光标左移三位。 |
| aa1aa bbbCC | 上移一行。当前列位置为 2,目标行长度为 4,2 < 4,所以光标列位置不变。 | |
| -- | aa1 bbbCC | 删除光标右侧的两个 'a'。光标位置不变,但现在它位于行尾。 |
| d@d | aaDd1 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); // 打印列表,会自动生成 "[...]" 格式
}
}