{ }codelper
读取一行P0347

给歌词加上行号

给出 n 行歌词。
歌词的一行可能是一个字符都没有的空行,也可能以若干个空格开头。
只给不是空行的行从上到下依次编号 1, 2, 3, …。
不是空行的行,按编号、冒号(:)、一个空格、该行内容的顺序连在一起输出在一行。
行的内容要和输入完全一样,开头的空格和中间的空格都照原样输出。
空行不加编号,照原样输出空行。
最后一行输出加了编号的行数和空行数,用一个空格隔开。
示例中第一行歌词以两个空格开头,第三行和第五行歌词是空行。

输入
第一行是 n(1 ≤ n ≤ 1,000,只给出数字,不带逗号),接下来 n 行每行是一行歌词。
一行歌词有 0~80 个字符,只由英文大小写字母、数字、空格和 .
, !
?
' 组成。
没有以空格结尾的行(所以也没有只含空格的行)。
最后一行歌词也可能是空行
输出
每行歌词对应一行,共 n 行,最后一行是加了编号的行数和空行数
样例 1 · stdin
5
  la la la
Twinkle, twinkle

How I wonder

stdout
1:   la la la
2: Twinkle, twinkle

3: How I wonder

3 2
main.py
输入(stdin)

运行时这些行会依次作为 input()/标准输入传入(运行中不会等待输入)。

$ 就绪

请在电脑上打开以编写和运行代码。在手机上可以查看题目和题解。

其他语言怎么写?查看各语言题解 · 8 种语言题解

把一行连同开头的空格整行读进来、并且把空行也算作一行的读取函数,各语言不一样。
Python 的 input()、Java 的 BufferedReader.readLine()、C# 的 Console.ReadLine()、C++ 的 getline(cin, s) 都返回去掉换行符的一行。
C 的 fgets 连换行符也放进来,所以要用 buf[strcspn(buf, "\n")] = '\0' 去掉。
JS、TS 把输入整个读进来,再用 split("\n") 分开。
Craykon 的 控制台.读行() 遇到空行返回 "",只有输入结束时才返回 空。
第一行的 n 也用同一个函数读一行再转成数(int(input())、atoi(buf)、stoi(line)、转数字()),就不会因为读数和读行混用而错行。
本题的陷阱都是平时没出过问题的习惯。
陷阱一:Python 里习惯性写的 input().strip() 会去掉行首的空格,示例的第一行变成 1: la la la。
陷阱二:Python 的 sys.stdin.readline() 和 input() 不同,不去掉换行符。
空行是 "\n",于是空行也被编号,示例的最后一行变成 5 0。
陷阱三:在 C 里像 scanf("%d ", &n) 这样加一个空格想吃掉剩下的换行符,这个空格吃掉的不是一个换行符,而是后面连续的所有空格和换行符。
示例的第一行变成 1: la la la,如果歌词以空行开头,这些空行也会消失。
陷阱四:C++ 的 cin >> n >> ws 同样会跳过后面连续的所有空格和换行符。
陷阱五:在 JS 里先对输入做 .trim() 再分割,末尾的空行就没了。
示例的第五行歌词变成 undefined,输出 4: undefined。
陷阱六:在 C# 里用 Split('\n', StringSplitOptions.RemoveEmptyEntries) 分割,空行全被丢掉,行数不够,在示例上会因 IndexOutOfRangeException 而停止。

Pythonmain.py · 12 行
n = int(input())numbered = 0empty = 0for _ in range(n):    line = input()  # 한 줄을 통째로: 앞 빈칸은 그대로, 줄 바꿈만 뗀다    if line == "":        empty += 1        print()    else:        numbered += 1        print(f"{numbered}: {line}")print(numbered, empty)
JavaScriptmain.js · 18 行
// 입력을 통째로 읽어 줄 바꿈으로만 나눈다. trim()을 하면 빈 줄과 앞 빈칸이 사라진다const lines = require("fs").readFileSync(0, "utf8").split("\n");const n = Number(lines[0]);let numbered = 0;let empty = 0;const out = [];for (let i = 1; i <= n; i++) {  const line = lines[i];  if (line === "") {    empty++;    out.push("");  } else {    numbered++;    out.push(`${numbered}: ${line}`);  }}out.push(`${numbered} ${empty}`);console.log(out.join("\n"));
TypeScriptmain.ts · 20 行
import { readFileSync } from "node:fs"; // 입력을 통째로 읽어 줄 바꿈으로만 나눈다. trim()을 하면 빈 줄과 앞 빈칸이 사라진다const lines: string[] = readFileSync(0, "utf8").split("\n");const n: number = Number(lines[0]);let numbered = 0;let empty = 0;const out: string[] = [];for (let i = 1; i <= n; i++) {  const line: string = lines[i];  if (line === "") {    empty++;    out.push("");  } else {    numbered++;    out.push(`${numbered}: ${line}`);  }}out.push(`${numbered} ${empty}`);console.log(out.join("\n"));
JavaMain.java · 24 行
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader; public class Main {    public static void main(String[] args) throws IOException {        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        int n = Integer.parseInt(br.readLine());        int numbered = 0, empty = 0;        StringBuilder sb = new StringBuilder();        for (int i = 0; i < n; i++) {            String line = br.readLine(); // 빈 줄은 ""로 온다(null은 입력이 끝났을 때만)            if (line.isEmpty()) {                empty++;            } else {                numbered++;                sb.append(numbered).append(": ").append(line);            }            sb.append('\n');        }        sb.append(numbered).append(' ').append(empty);        System.out.println(sb);    }}
C#Main.cs · 28 行
using System;using System.Text; class Program{    static void Main()    {        int n = int.Parse(Console.ReadLine()!);        int numbered = 0, empty = 0;        var sb = new StringBuilder();        for (int i = 0; i < n; i++)        {            string line = Console.ReadLine()!; // 빈 줄은 ""로 온다(null은 입력이 끝났을 때만)            if (line == "")            {                empty++;            }            else            {                numbered++;                sb.Append(numbered).Append(": ").Append(line);            }            sb.Append('\n');        }        sb.Append(numbered).Append(' ').Append(empty);        Console.WriteLine(sb);    }}
C++main.cpp · 23 行
#include <iostream>#include <string>using namespace std; int main() {    string line;    // 첫 줄의 수도 getline으로 읽는다: cin >> n과 섞지 않으면 줄이 밀리지 않는다    getline(cin, line);    int n = stoi(line);    int numbered = 0, empty = 0;    for (int i = 0; i < n; i++) {        getline(cin, line); // 앞 빈칸까지 한 줄을 통째로, 줄 바꿈은 빼고        if (line.empty()) {            empty++;            cout << '\n';        } else {            numbered++;            cout << numbered << ": " << line << '\n';        }    }    cout << numbered << ' ' << empty << '\n';    return 0;}
Cmain.c · 24 行
#include <stdio.h>#include <stdlib.h>#include <string.h> int main(void) {    char buf[128];    /* 첫 줄의 수도 fgets로 읽는다: scanf("%d")와 섞지 않으면 줄이 밀리지 않는다 */    if (!fgets(buf, sizeof buf, stdin)) return 0;    int n = atoi(buf);    int numbered = 0, empty = 0;    for (int i = 0; i < n; i++) {        if (!fgets(buf, sizeof buf, stdin)) return 0;        buf[strcspn(buf, "\n")] = '\0'; /* fgets가 담아 준 줄 바꿈을 지운다 */        if (buf[0] == '\0') {            empty++;            printf("\n");        } else {            numbered++;            printf("%d: %s\n", numbered, buf);        }    }    printf("%d %d\n", numbered, empty);    return 0;}
Craykonmain.cray · 18 行
n = 控制台.读行().转数字();numbered = 0;empty = 0;循环 (i = 0; i < n; i++){    line = 控制台.读行(); // 빈 줄은 ""로 온다(빈값은 입력이 끝났을 때만)    如果 (line == "")    {        empty += 1;        控制台.输出("");    }    否则    {        numbered += 1;        控制台.输出(numbered + ": " + line);    }}控制台.输出(numbered + " " + empty);