OD统一考试(C卷)
分值: 200分
题解: Java / Python / C++
题目描述
有一个文件, 包含以一定规则写作的文本, 请统计文件中包含的文本数量
规则如下
- 文本以";“分隔,最后一条可以没有”;",但空文本不能算语句,比如"COMMAND A; ;"只能算一条语句.
注意, 无字符/空白字符/制表符都算作"空"文本 - 文本可以跨行, 比如下面, 是一条文本, 而不是三条
COMMAND A
AND
COMMAND B; - 文本支持字符串, 字符串为成对的单引号(')或者成对的双引号(“), 字符串可能出现用转义字符(\)处理的单双引号(比如"your input is: \”")和转义字符本身, 比如
COMMAND A “Say \“hello\””; - 支持注释, 可以出现在字符串之外的任意位置, 注释以"–“开头, 到换行结束, 比如
COMMAND A; – this is comment
COMMAND – comment
A AND COMMAND B;
注意, 字符串内的”–", 不是注释
输入描述
文本文件
输出描述
包含的文本数量
示例1
输入:
COMMAND TABLE IF EXISTS "UNITED STATE";
COMMAND A GREAT (
ID ADSAB,
download_length INTE-GER, -- test
file_name TEXT,
guid TEXT,
mime_type TEXT,
notifica-tionid INTEGER,
original_file_name TEXT,
pause_reason_type INTEGER,
resumable_flag INTEGER,
start_time INTEGER,
state INTEGER,
folder TEXT,
path TEXT,
total_length INTE-GER,
url TEXT
);
输出:
2
题解
这个问题可以通过使用有限状态机(Finite State Machine, FSM)来解决。
我们可以定义四种状态:正常文本、双引号字符串、单引号字符串和注释内容。
然后,我们遍历输入的每一行,根据当前字符和状态来决定下一个状态以及是否需要增加文本计数。
Java
java">/**
* @author code5bug
*/
public class Main {
enum State { // 表示四种状态:双引号字符串,单引号字符串,注释内容, 正常文本
DoubleStr, SingleStr, Comment, Normal
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
// 前一个字符, 这次初始化为 ';' 是为了避免第一个字符就是 ';' 导致文本计机数不准
char pre = ';';
State state = State.Normal;
int result = 0;
while (in.hasNext()) {
char[] cs = in.nextLine().toCharArray();
for (char c : cs) {
if (Character.isWhitespace(c)) continue; // 空白符
if (state == State.Normal) {
if (pre == '-' && c == '-') { // 注释内容
state = State.Comment;
} else if (c == '\"') { // 双引号开始的字符串
state = State.DoubleStr;
} else if (c == '\'') { // 单引号开始的字符串
state = State.SingleStr;
} else if (c == ';') { // 遇到分割符
// 不是相邻的 ';' 则 + 1
if (pre != ';') result++;
}
} else if (state == State.DoubleStr && c == '\"') { // 字符串双引号结束
state = State.Normal;
} else if (state == State.SingleStr && c == '\'') { // 字符串单引号结束
state = State.Normal;
}
pre = c;
}
if (state == State.Comment) { // 注释只到行结尾
state = State.Normal;
}
}
if (pre != ';') result++; // 结尾的 ;
System.out.println(result);
}
}
Python
python">import sys
# 表示四种状态:双引号字符串,单引号字符串,注释内容, 正常文本
DoubleStr, SingleStr, Comment, Normal = 1, 2, 3, 4
text_cnt = 0 # 文本计数器
state = Normal # 初始状态为正常文本
pre = ';' # 前一个字符, 这次初始化为 ';' 是为了避免第一个字符就是 ';' 导致文本计机数不准
for line in sys.stdin:
for c in line:
# 如果 c 为空字符\制表符
if c.isspace():
continue
if state == Normal:
if c == '"': # 开始双引号字符串
state = DoubleStr
elif c == "'": # 开始单引号字符串
state = SingleStr
elif c == '-' and pre == '-': # 开始注释内容
state = Comment
elif c == ';' and pre != ';': # 遇到; 分割
text_cnt += 1
elif state == DoubleStr and c == '"': # 双引号字符串结束
state = Normal
elif state == SingleStr and c == "'": # 单引号字符串结束
state = Normal
pre = c
# 注释只到行结尾
if state == Comment:
state = Normal
# 结尾的 ; 分割
if pre != ';':
text_cnt += 1
print(text_cnt)
C++
#include <bits/stdc++.h>
using namespace std;
enum class State
{
// 双引号字符串, 单引号字符串, 注释, 正常文本
double_str,
single_str,
comment,
normal
};
int main()
{
int text_cnt = 0; // 文本数量
string line;
State state = State::normal;
// 前一个字符, 这次初始化为 ';' 是为了避免第一个字符就是 ';' 导致文本计机数不准
char pre = ';';
while (getline(cin, line)) {
for (char c : line) {
// 空字符
if (isspace(c)) continue;
if (state == State::normal) {
if (c == '"') { // 开始双引号字符串
state = State::double_str;
} else if (c == '\'') { // 开始单引号字符串
state = State::single_str;
} else if (c == '-' && pre == '-') { // 开始注释内容
state = State::comment;
} else if (c == ';' && pre != ';') { // 遇到; 分割
text_cnt++;
}
} else if (state == State::double_str && c == '"') { // 双引号字符串结束
state = State::normal;
} else if (state == State::single_str && c == '\'') { // 单引号字符串结束
state = State::normal;
}
pre = c;
}
if (state == State::comment) {
state = State::normal;
}
}
// 结尾的 ;
if (pre != ';') text_cnt++;
cout << text_cnt << endl;
return 0;
}
🙏整理题解不易, 如果有帮助到您,请给点个赞 ❤️ 和收藏 ⭐,让更多的人看到。🙏🙏🙏