题目描述
有一个文件,包含以一定规则写作的文本,请统计文件中包含的文本数量。
规则如下:
1. 文本以”;”分隔,最后一条可以没有”;”,但空文本不能算语句,比如”COMMAND A; ;”只能算一条语句。注意,无字符/空白字符/制表符都算作”空”文本;
2. 文本可以跨行,比如下面,是一条文本,而不是三条;
COMMAND A
AND
COMMAND B;
3. 文本支持字符串,字符串为成对的单引号(')或者成对的双引号("),字符串可能出现用转义字符()处理的单双引号("your input is"")和转义字符本身,比如
COMMAND A "Say "hello"";
4. 支持注释,可以出现在字符串之外的任意位置注释以”-“开头,到换行结束,比如:
COMMAND A; -this is comment
COMMAND -comment
A AND COMMAND B;
注意字符串内的”-“,不是注释。
输入描述
文本文件
输出描述
包含的文本数量
用例
输入 |
COMMAND TABLE IF EXISTS "UNITED STATE"; |
输出 | 2 |
说明 | 无 |
题目解析
梳理一下题目信息:
- 一行中可以有多条文本,比如一行输入为:abc;abc;abc; 此时该行有三条文本。
- 一条文本以分号结束
- 成对双引号、成对单引号中的分号,无法作为一条文本结束的标志
- 注释符号后面的分号,无法作为一条文本结束的标志
- 成对双引号、成对单引号中的注释符号失效
- 成对双引号、成对单引号中可能存在转义字符
本题要我们求解文本条数,其实可以转化为求解有效分号个数。
而无效分号,其实就是:
- 成对双引号、成对单引号中的分号
- 注释符号后面的分号
我的解题思路如下,假设一行字符串为line:
- 首先,将line中的转义双引号、转义单引号去掉,避免影响成对双引号、成对单引号的判断
- 然后,将line中的成对双引号及其中内容、成对单引号及其中内容去除,这样可以简单粗暴的去除成对双引号、成对单引号中的注释符号、分号
- 之后,将line中注释内容(即:‘-’及其后内容)去掉,这样可以简单粗暴的去除注释中的分号
- 此时line中就只会剩下分号,我们需要处理一些特殊情况,比如空文本不能算语句,我们可以将line中的空白字符去除掉
- 经过上一步处理,如果line中存在空白文本,则去除空白字符后,必然会出现类似于 abc;; 这种连续分号的现象,此时我们应该将连续分号替换为单个分号
- 经过上一步处理,还有一种特殊情况,比如 ;abc 这种,我们需要去除开头分号
- 最后,line中剩余几个分号,就代表此行存在几个文本
上面逻辑,如果使用字符串操作来写,则较为复杂,我这里直接使用了正则表达式来处理。
另外,需要注意的是,题目描述中说
文本以”;”分隔,最后一条可以没有”;”
这句话的意思应该是,最后一行输入中的最后一条文本,可以没有分号。
比如最后一行为 abc;abc
此时最后一行其实有两条文本,因为最后一条可以没有分号。
关于最后一行,我们可以粗暴的直接给它拼接一个分号,这样话,无论最后一行的最后一条有没有分号,我们都能保证前面的逻辑可以统计到最后一行。
2023.09.05 根据考友提示,上面逻辑存在漏洞,成对双引号、成对单引号之间的内容不能直接替换为空串,因为对于如下情况:
"abc";"abc";"abc";
其实应该是3行。
我们可以将成对双引号、成对单引号之间的内容替换为简单串,比如a
JavaScript算法源码
/* JavaScript Node ACM模式 控制台输入获取 */
const readline = require("readline");
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
const lines = [];
rl.on("line", (line) => {
if (line === "") {
console.log(getResult(lines));
lines.length = 0;
} else {
lines.push(line);
}
});
function getResult(lines) {
let s = lines
.map(
(line) =>
line
.replaceAll(/\\["']/g, "") // 替换"和'为空串
.replaceAll(/".*?"/g, "a") // 将成对双引号及其中内容替换为空串
.replaceAll(/'.*?'/g, "a") // 将成对单引号及其中内容替换为空串
.replaceAll(/-.+/g, "") // 将-往后的注释替换为空串
.replaceAll(/s+/g, "") // 将空白字符替换为空串
.replaceAll(/;+/g, ";") // 将连续分号替换为单个分号
)
.join("");
// 题目描述说:文本以”;”分隔,最后一条可以没有”;”
// 为了避免复杂处理,这里无论最后一条文本有没有分号,都加一个
s += ";";
// 下面处理主要是为了处理跨行文本
/***
* 比如
* aaaa;
* ;aaaa
*
* 比如
* ;aaaa
* ;aaaa
*/
s = s.replaceAll(/;+/g, ";").replaceAll(/^;/g, "");
// 记录文本条数
let count = 0;
for (let c of s) {
if (c == ";") count++; // 此时一行有几个分号,就代表几条文本
}
return count;
}
Java算法源码
import java.util.LinkedList;
import java.util.Scanner;
public class Main {
// 输入获取
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
LinkedList<String> lines = new LinkedList<>();
while (sc.hasNextLine()) {
String line = sc.nextLine();
if ("".equals(line)) {
System.out.println(getResult(lines));
sc.close();
break;
} else {
lines.add(line);
}
}
}
// 算法入口
public static int getResult(LinkedList<String> lines) {
StringBuilder sb = new StringBuilder();
for (String line : lines) {
line =
line.replaceAll("\\["']", "") // 替换"和'为空串
.replaceAll("".*?"", "a") // 将成对双引号及其中内容替换为空串
.replaceAll("'.*?'", "a") // 将成对单引号及其中内容替换为空串
.replaceAll("-.+", "") // 将-往后的注释替换为空串
.replaceAll("\s+", "") // 将空白字符替换为空串
.replaceAll(";+", ";"); // 将连续分号替换为单个分号
sb.append(line);
}
// 题目描述说:文本以”;”分隔,最后一条可以没有”;”
// 为了避免复杂处理,这里无论最后一条文本有没有分号,都加一个
sb.append(";");
// 下面处理主要是为了处理跨行文本
/***
* 比如
* aaaa;
* ;aaaa
*
* 比如
* ;aaaa
* ;aaaa
*/
String s = sb.toString().replaceAll(";+", ";").replaceAll("^;", "");
// 记录文本条数
int count = 0;
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == ';') count++;
}
return count;
}
}
Python算法源码
# 算法入口
import re
def fn(s):
s = re.sub("\["']", "", s) # 替换"和'为空串
s = re.sub("".*?"", "a", s) # 将成对双引号及其中内容替换为空串
s = re.sub("'.*?'", "a", s) # 将成对单引号及其中内容替换为空串
s = re.sub("-.+", "", s) # 将-往后的注释替换为空串
s = re.sub("\s+", "", s) # 将空白字符替换为空串
s = re.sub(";+", ";", s) # 将连续分号替换为单个分号
return s
def getResult(lines):
s = "".join(map(fn, lines))
# 题目描述说:文本以”;”分隔,最后一条可以没有”;”
# 为了避免复杂处理,这里无论最后一条文本有没有分号,都加一个
s += ";"
# 下面处理主要是为了处理跨行文本
"""
比如
aaaa;
;aaaa
比如
;aaaa
;aaaa
"""
s = re.sub(";+", ";", s)
s = re.sub("^;", "", s)
# 记录文本条数
count = 0
for c in s:
if c == ';':
count += 1 # 此时一行有几个分号,就代表几条文本
return count
# 输入获取
lines = []
while True:
line = input()
if line != "":
lines.append(line)
else:
print(getResult(lines))
break
免责声明:
评论0