In a settings file, a long entry is split over several lines by putting a backslash (\) at the end of a line to continue on the next one.
Read the input line by line to the end and unfold the continued lines into single lines.
Each line of the input is called an 'input line', numbered from 1.
If the last character of an input line is a backslash, that line is a 'continuing line'.
For a continuing line, remove only that one final backslash and append the content of the very next input line as it is.
If the next input line is also a continuing line, repeat the same thing; once an input line that is not a continuing line has been appended, one 'unfolded line' is complete.
Whether a line is a continuing line is decided by looking at that single input line, not at the joined string.
Even if a line ends with several backslashes, only the last one is removed, and a line with a space after the backslash is not a continuing line.
If the last line of the input is a continuing line, remove its one backslash and end the unfolded line there.
An empty line is also an input line, and spaces at the start or end of a line are content and are not removed.
For each unfolded line print one line: the number of the input line where it started, a single space, and the content enclosed in square brackets [ and ].
On the last line print the number of input lines and the number of unfolded lines, separated by a single space.
Input
The input has between 1 and 1,000 lines; the number of lines is not given. Each line has 0 to 100 characters, all with ASCII codes 32 (space) to 126. Every line, including the last, ends with a newline
Output
For each unfolded line print start-number [content] on its own line; then print the number of input lines and the number of unfolded lines on the last line, separated by a single space
When you run, these lines are fed to input()/stdin in order (the program doesn't stop to ask).
$ Ready
Open this on a computer to write and run code. On mobile you can read the problem and the solutions.
In other languagesShow solutions by language · 8 languages
The number of lines is not given, so each language gets its own 'no more lines' signal. In Python for line in sys.stdin: simply ends (input() raises EOFError at the end); Java readLine() and C# Console.ReadLine() return null, C fgets returns NULL, C++ std::getline becomes false, and Craykon Console.ReadLine() returns null. JavaScript and TypeScript read everything and split it with split("\n"). Whether the line comes with its newline also differs: Python's line and C's fgets keep the newline, so you remove it yourself; the others remove it for you. The backslash character has to be written twice to mean one, "\\", in all eight languages ('\\' for a C/C++ character). The last character is asked for with Python line.endswith(…), JS/TS line.endsWith(…), Java endsWith, C# EndsWith, C++ line.back(), C line[len - 1] and Craykon line.EndsWith(…). Eight traps: ① Using line.strip() in Python to drop the newline also deletes spaces at both ends. Line 5 of the example has a space after the backslash and so does not continue, but with the space gone it is joined to line 6. Remove only the newline with rstrip("\n"). ② Removing the backslash with line.rstrip(…) deletes every backslash at the end. Line 3 of the example must keep one backslash. Cut exactly one character, as in line[:-1]. ③ JS split("\n") produces one more empty string after the final newline. Counting it adds a line that does not exist. Drop it with pop(). ④ But calling trim() on the whole input also removes the spaces before the first line and the real empty lines at the very end. ⑤ Treating an empty line as the end of input. In Craykon an empty line is "" and the end of input is null; they are different. Stopping at line == "" ends the reading at line 4 of the example. ⑥ Deciding from the end of the joined string: after line 3 of the example leaves one backslash and the empty line 4 is appended, the joined string still ends with a backslash, so it looks like a continuing line and line 5 is joined as well. Decide from the single input line. ⑦ In Java, reading the line after a continuing line and calling endsWith on it without checking for null stops with a NullPointerException on the example, whose last line ends with a backslash. ⑧ The C fgets buffer must hold 100 characters, the newline and the terminator: at least 102 bytes. With char line[101], a 100-character line pushes its newline to the next read, and one extra empty line is read.
Pythonmain.py · 29 lines
import sysdef 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 lines
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 lines
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 lines
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 lines
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 lines
#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 lines
#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 lines
physical = 0;logical = 0;start = 0;text = "";open = false; // 앞줄이 역슬래시로 끝나 아직 이어지는 중인가while (true){ line = Console.ReadLine(); if (line == null) { break; } physical += 1; if (!open) { start = physical; text = ""; } if (line.EndsWith("\\")) { text += line.Substring(0, line.Length - 1); // 마지막 역슬래시 하나만 뗀다 open = true; } else { text += line; Console.WriteLine(start + " [" + text + "]"); logical += 1; open = false; }}if (open){ Console.WriteLine(start + " [" + text + "]"); logical += 1;}Console.WriteLine(physical + " " + logical);