(C卷,200分)- 文本统计分析(Java & JS & Python)

题目描述

有一个文件,包含以一定规则写作的文本,请统计文件中包含的文本数量。

规则如下:

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";
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
说明

题目解析

梳理一下题目信息:

  • 一行中可以有多条文本,比如一行输入为:abc;abc;abc; 此时该行有三条文本。
  • 一条文本以分号结束
  • 成对双引号、成对单引号中的分号,无法作为一条文本结束的标志
  • 注释符号后面的分号,无法作为一条文本结束的标志
  • 成对双引号、成对单引号中的注释符号失效
  • 成对双引号、成对单引号中可能存在转义字符

本题要我们求解文本条数,其实可以转化为求解有效分号个数。

而无效分号,其实就是:

  • 成对双引号、成对单引号中的分号
  • 注释符号后面的分号

我的解题思路如下,假设一行字符串为line:

  1. 首先,将line中的转义双引号、转义单引号去掉,避免影响成对双引号、成对单引号的判断
  2. 然后,将line中的成对双引号及其中内容、成对单引号及其中内容去除,这样可以简单粗暴的去除成对双引号、成对单引号中的注释符号、分号
  3. 之后,将line中注释内容(即:‘-’及其后内容)去掉,这样可以简单粗暴的去除注释中的分号
  4. 此时line中就只会剩下分号,我们需要处理一些特殊情况,比如空文本不能算语句,我们可以将line中的空白字符去除掉
  5. 经过上一步处理,如果line中存在空白文本,则去除空白字符后,必然会出现类似于 abc;; 这种连续分号的现象,此时我们应该将连续分号替换为单个分号
  6. 经过上一步处理,还有一种特殊情况,比如 ;abc 这种,我们需要去除开头分号
  7. 最后,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

免责声明:

1、IT资源小站为非营利性网站,全站所有资料仅供网友个人学习使用,禁止商用
2、本站所有文档、视频、书籍等资料均由网友分享,本站只负责收集不承担任何技术及版权问题
3、如本帖侵犯到任何版权问题,请立即告知本站,本站将及时予与删除下载链接并致以最深的歉意
4、本帖部分内容转载自其它媒体,但并不代表本站赞同其观点和对其真实性负责
5、一经注册为本站会员,一律视为同意网站规定,本站管理员及版主有权禁止违规用户
6、其他单位或个人使用、转载或引用本文时必须同时征得该帖子作者和IT资源小站的同意
7、IT资源小站管理员和版主有权不事先通知发贴者而删除本文

0

评论0

站点公告

没有账号?注册  忘记密码?