{ }codelper
한 줄 읽기입력 끝까지 읽기P0325

역슬래시로 이어 쓴 줄 펴기

설정 파일에서는 긴 내용을 여러 줄에 나눠 쓸 때 줄 끝에 역슬래시(\)를 붙여 다음 줄로 이어 쓴다. 입력을 끝까지 한 줄씩 읽어, 이어 쓴 줄들을 한 줄로 펴라. 입력의 줄 하나하나를 '입력 줄'이라 하고, 1번부터 번호를 붙인다. 입력 줄의 마지막 문자가 역슬래시이면 그 줄은 '이어지는 줄'이다. 이어지는 줄에서는 마지막 역슬래시 하나만 떼어 내고, 바로 다음 입력 줄의 내용을 그대로 뒤에 붙인다. 다음 입력 줄도 이어지는 줄이면 같은 일을 되풀이하고, 이어지는 줄이 아닌 입력 줄을 붙이고 나면 '편 줄' 하나가 끝난다. 이어지는 줄인지는 붙여 만든 문자열이 아니라 입력 줄 하나만 보고 정한다. 줄 끝에 역슬래시가 여러 개 있어도 마지막 하나만 떼어 내고, 역슬래시 뒤에 빈칸이 있는 줄은 이어지는 줄이 아니다. 입력의 마지막 줄이 이어지는 줄이면 역슬래시 하나만 떼어 내고 거기서 편 줄을 끝낸다. 빈 줄도 입력 줄 하나이고, 줄의 앞뒤 빈칸도 내용이므로 지우지 않는다. 편 줄마다 한 줄씩, 그 편 줄이 시작한 입력 줄의 번호, 빈칸 하나, 그리고 대괄호 [와 ]로 감싼 내용을 출력한다. 마지막 줄에는 입력 줄의 수와 편 줄의 수를 빈칸 하나로 띄워 출력한다.

입력
입력은 1줄 이상 1,000줄 이하이고, 줄 수는 따로 주어지지 않는다.
각 줄은 0자 이상 100자 이하이며 아스키 코드 32(빈칸)부터 126까지의 문자로만 이루어진다.
마지막 줄을 포함한 모든 줄은 줄바꿈으로 끝난다
출력
편 줄마다 시작 번호 [내용]을 한 줄씩 출력하고, 마지막 줄에 입력 줄의 수와 편 줄의 수를 빈칸 하나로 띄워 출력한다
예시 1 · stdin
total = price \
  + tax
path C:\temp\\

  note \ 
end\
stdout
1 [total = price   + tax]
3 [path C:\temp\]
5 [  note \ ]
6 [end]
6 4
main.py
입력(stdin)

실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).

$ 준비됐어요

코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.

다른 언어로는?언어별 풀이 보기 · 8개 언어 풀이

줄 수를 알려 주지 않으니 '더 읽을 줄이 없다'는 신호를 언어마다 다르게 받아요.
Python은 for line in sys.stdin:이 스스로 끝나고(input()은 끝에서 EOFError를 내요), Java readLine()과 C# Console.ReadLine()은 null, C fgets는 NULL, C++ std::getline은 거짓, 크레이콘 콘솔.줄읽기()는 빈값을 돌려줘요.
JavaScript·TypeScript는 전체를 읽어 split("\n")으로 나눠요.
읽은 줄에 줄바꿈이 붙어 오는지도 달라요: Python의 line과 C의 fgets는 줄바꿈까지 담아 주니 직접 떼고, 나머지는 떼어서 줘요.
역슬래시 문자는 여덟 언어 모두 "\\"처럼 두 번 써야 하나예요(C·C++의 문자는 '\\').
끝 문자는 Python line.endswith(…), JS·TS line.endsWith(…), Java endsWith, C# EndsWith, C++ line.back(), C line[len - 1], 크레이콘 line.끝나나(…)로 물어요.
함정 여덟: ① Python에서 줄바꿈을 떼려고 line.strip()을 쓰면 앞뒤 빈칸까지 지워져요.
예시 5번 줄은 역슬래시 뒤에 빈칸이 있어 이어지지 않는데, 빈칸이 지워지면 6번 줄과 붙어요.
rstrip("\n")으로 줄바꿈만 떼요.
② 역슬래시를 line.rstrip(…)으로 떼면 끝에 이어진 역슬래시가 전부 사라져요.
예시 3번 줄은 역슬래시 하나가 남아야 해요.
line[:-1]처럼 한 문자만 떼요.
③ JS의 split("\n")은 마지막 줄바꿈 뒤에 빈 문자열을 하나 더 만들어요.
그대로 세면 없는 줄이 하나 늘어요.
pop()으로 버려요.
④ 그렇다고 입력 전체에 trim()을 걸면 첫 줄 앞의 빈칸과 맨 끝의 진짜 빈 줄들까지 사라져요.
⑤ 빈 줄을 입력의 끝으로 여기는 일이에요.
크레이콘에서 빈 줄은 "", 입력의 끝은 빈값으로 서로 달라요.
line == ""에서 멈추면 예시 4번 줄에서 읽기가 끝나요.
⑥ 붙여 만든 문자열의 끝을 보고 이어지는지 정하면, 예시 3번 줄에서 남겨 둔 역슬래시 뒤에 빈 줄(4번)이 붙었을 때 또 이어지는 줄로 보여 5번 줄까지 붙어요.
입력 줄 하나만 보고 정해요.
⑦ Java에서 이어지는 줄의 다음 줄을 읽고 null인지 보지 않은 채 endsWith를 부르면, 마지막 줄이 역슬래시로 끝나는 예시에서 NullPointerException으로 멈춰요.
⑧ C의 fgets 버퍼는 100자 + 줄바꿈 + 끝 표시까지 102칸이 넘어야 해요.
char line[101]이면 100자짜리 줄에서 줄바꿈이 다음 읽기로 밀려 빈 줄이 하나 더 읽혀요.

Pythonmain.py · 29 줄
import sys  def main():    out = []    physical = 0    start = 0    parts = []    open_line = False  # 앞줄이 역슬래시로 끝나 아직 이어지는 중인가    for line in sys.stdin:  # 입력이 끝나면 반복도 끝난다        line = line.rstrip("\n")  # 줄바꿈만 뗀다. strip()은 앞뒤 빈칸까지 지운다        physical += 1        if not open_line:            start = physical            parts = []        if line.endswith("\\"):            parts.append(line[:-1])  # 마지막 역슬래시 하나만 뗀다            open_line = True        else:            parts.append(line)            out.append(f"{start} [{''.join(parts)}]")            open_line = False    if open_line:  # 마지막 줄이 역슬래시로 끝났다        out.append(f"{start} [{''.join(parts)}]")    out.append(f"{physical} {len(out)}")    print("\n".join(out))  main()
JavaScriptmain.js · 25 줄
const lines = require("fs").readFileSync(0, "utf8").split("\n");lines.pop(); // 마지막 줄바꿈 뒤에 생기는 빈 문자열은 줄이 아니다 const out = [];let start = 0;let text = "";let open = false; // 앞줄이 역슬래시로 끝나 아직 이어지는 중인가for (let i = 0; i < lines.length; i++) {  const line = lines[i];  if (!open) {    start = i + 1;    text = "";  }  if (line.endsWith("\\")) {    text += line.slice(0, -1); // 마지막 역슬래시 하나만 뗀다    open = true;  } else {    text += line;    out.push(`${start} [${text}]`);    open = false;  }}if (open) out.push(`${start} [${text}]`); // 마지막 줄이 역슬래시로 끝났다out.push(`${lines.length} ${out.length}`);console.log(out.join("\n"));
TypeScriptmain.ts · 26 줄
import { readFileSync } from "node:fs"; const lines: string[] = readFileSync(0, "utf8").split("\n");lines.pop(); // 마지막 줄바꿈 뒤에 생기는 빈 문자열은 줄이 아니다 const out: string[] = [];let start = 0;let text = "";let open = false; // 앞줄이 역슬래시로 끝나 아직 이어지는 중인가lines.forEach((line: string, i: number) => {  if (!open) {    start = i + 1;    text = "";  }  if (line.endsWith("\\")) {    text += line.slice(0, -1); // 마지막 역슬래시 하나만 뗀다    open = true;  } else {    text += line;    out.push(`${start} [${text}]`);    open = false;  }});if (open) out.push(`${start} [${text}]`); // 마지막 줄이 역슬래시로 끝났다out.push(`${lines.length} ${out.length}`);console.log(out.join("\n"));
JavaMain.java · 34 줄
import java.io.*; public class Main {    public static void main(String[] args) throws IOException {        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        StringBuilder out = new StringBuilder();        StringBuilder text = new StringBuilder();        int physical = 0, logical = 0, start = 0;        boolean open = false; // 앞줄이 역슬래시로 끝나 아직 이어지는 중인가        String line;        while ((line = br.readLine()) != null) { // 입력이 끝나면 null을 돌려준다            physical++;            if (!open) {                start = physical;                text.setLength(0);            }            if (line.endsWith("\\")) {                text.append(line, 0, line.length() - 1); // 마지막 역슬래시 하나만 뗀다                open = true;            } else {                text.append(line);                out.append(start).append(" [").append(text).append("]\n");                logical++;                open = false;            }        }        if (open) { // 마지막 줄이 역슬래시로 끝났다            out.append(start).append(" [").append(text).append("]\n");            logical++;        }        out.append(physical).append(' ').append(logical).append('\n');        System.out.print(out);    }}
C#Main.cs · 42 줄
using System;using System.Text; class Program{    static void Main()    {        var output = new StringBuilder();        var text = new StringBuilder();        int physical = 0, logical = 0, start = 0;        bool open = false; // 앞줄이 역슬래시로 끝나 아직 이어지는 중인가        string? line;        while ((line = Console.ReadLine()) != null) // 입력이 끝나면 null을 돌려준다        {            physical++;            if (!open)            {                start = physical;                text.Clear();            }            if (line.EndsWith('\\'))            {                text.Append(line, 0, line.Length - 1); // 마지막 역슬래시 하나만 뗀다                open = true;            }            else            {                text.Append(line);                output.Append(start).Append(" [").Append(text).Append("]\n");                logical++;                open = false;            }        }        if (open) // 마지막 줄이 역슬래시로 끝났다        {            output.Append(start).Append(" [").Append(text).Append("]\n");            logical++;        }        output.Append(physical).Append(' ').Append(logical).Append('\n');        Console.Write(output);    }}
C++main.cpp · 31 줄
#include <iostream>#include <string> int main() {    std::ios::sync_with_stdio(false);    std::string line, text;    int physical = 0, logical = 0, start = 0;    bool open = false; // 앞줄이 역슬래시로 끝나 아직 이어지는 중인가    while (std::getline(std::cin, line)) { // 입력이 끝나면 거짓이 된다. 줄바꿈은 떼어 준다        physical++;        if (!open) {            start = physical;            text.clear();        }        if (!line.empty() && line.back() == '\\') {            line.pop_back(); // 마지막 역슬래시 하나만 뗀다            text += line;            open = true;        } else {            text += line;            std::cout << start << " [" << text << "]\n";            logical++;            open = false;        }    }    if (open) { // 마지막 줄이 역슬래시로 끝났다        std::cout << start << " [" << text << "]\n";        logical++;    }    std::cout << physical << ' ' << logical << '\n';}
Cmain.c · 31 줄
#include <stdbool.h>#include <stdio.h>#include <string.h> int main(void) {    char line[128]; // 100자 + 줄바꿈 + 끝 표시('\0')가 들어가야 한다    int physical = 0, logical = 0;    bool open = false; // 앞줄이 역슬래시로 끝나 아직 이어지는 중인가    while (fgets(line, sizeof line, stdin) != NULL) { // 입력이 끝나면 NULL을 돌려준다        size_t len = strlen(line);        if (len > 0 && line[len - 1] == '\n') line[--len] = '\0'; // fgets는 줄바꿈까지 담아 준다        physical++;        if (!open) {            // 이은 줄을 모아 두지 않고, 읽는 대로 이어서 출력한다            printf("%d [", physical);            logical++;        }        if (len > 0 && line[len - 1] == '\\') {            line[len - 1] = '\0'; // 마지막 역슬래시 하나만 뗀다            fputs(line, stdout);            open = true;        } else {            fputs(line, stdout);            puts("]");            open = false;        }    }    if (open) puts("]"); // 마지막 줄이 역슬래시로 끝났다    printf("%d %d\n", physical, logical);    return 0;}
Craykonmain.cray · 37 줄
physical = 0;logical = 0;start = 0;text = "";open = 거짓; // 앞줄이 역슬래시로 끝나 아직 이어지는 중인가동안 (참){    line = 콘솔.줄읽기();    만약 (line == 빈값)    {        그만;    }    physical += 1;    만약 (!open)    {        start = physical;        text = "";    }    만약 (line.끝나나("\\"))    {        text += line.부분문자열(0, line.길이 - 1); // 마지막 역슬래시 하나만 뗀다        open = 참;    }    아니면    {        text += line;        콘솔.쓰기(start + " [" + text + "]");        logical += 1;        open = 거짓;    }}만약 (open){    콘솔.쓰기(start + " [" + text + "]");    logical += 1;}콘솔.쓰기(physical + " " + logical);