{ }codelper
1行読み込み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);