{ }codelper
部分文字列文字列の連結P0104

幅に合わせて折り返す

一行目に幅 w が与えられ、次の行から入力の終わりまで本文が与えられる。
本文の単語とは、空白(スペース、タブ、改行)でない文字が続いたかたまりである。
単語を順に行に入れて出力せよ。
同じ行の単語の間には空白を一つだけ置き、行の前後には空白を置かない。
次の単語を空白一つと一緒に付けたとき行の長さが w を超えるなら、その単語から新しい行に書く。
ちょうど w になるなら同じ行に書く。
w より長い単語は前から w 文字ずつ切って切れ端を作り(最後の切れ端は短いことがある)、切れ端一つ一つを単語のように扱う。
本文の改行や空の行は結果に影響しない。

入力
1 ≤ w ≤ 80。
本文は 8,000 文字以下で、単語が一つ以上ある。
単語は印字可能な ASCII 文字からなる
出力
折り返した行
例 1 · stdin
10
The quick  brown fox

jumps over a supercalifragilistic dog.
stdout
The quick
brown fox
jumps over
a
supercalif
ragilistic
dog.
main.py
入力(stdin)

実行すると、これらの行が順に input()・標準入力に渡されます(実行中に入力を求めません)。

$ 準備完了

コードを入力して解くにはパソコンで開いてください。モバイルでは問題と解答を見られます。

ほかの言語では?言語別の解答を見る · 8 言語の解答

行ごとに単語をリストに集めてから空白一つでつなぐ(join)と、行末に空白が残りません:Python " ".join(line)、JS・TS line.join(" ")、Java String.join(" ", line)、C# string.Join(" ", line)。
はみ出すかは 今の長さ + 1 + 単語の長さ > w で聞きます。
>= にすると、ちょうど w の行も一語早く折り返します。
単語の分け方では JS split(" ") が落とし穴です。
空白が重なった所に空の単語 "" を作り、タブでは分けません。
trim().split(/\s+/)、Python split()、C# Split((char[])null, RemoveEmptyEntries)、C scanf("%s")、C++ >> は空白のかたまりを一度に飛ばします。
本文は複数行なので、最初の行だけでなく入力の終わりまで読みます。
長い単語を切るとき、Python word[i:i+w]、JS slice、C++ substr(i, w) は終わりを越えるとそこで止まります。
C# Substring(i, w) と Java substring(i, i + w) は例外になるので、Math.Min・Math.min で残りの長さを渡します。
長い単語を切らずに置いたり、Python textwrap.wrap を使ったりしてはいけません。
textwrap は長い単語を今の行の残りの欄から詰めるので、この問題の規則(切れ端は w 文字ずつ)と違います。
Craykon 切り出す(開始, 個数) も C# のように終わりを越えるとエラーなので 数学.小さい方(w, word.長さ - i) を渡し、行は line.つなぐ(" ") でつなぎます。

Pythonmain.py · 18 行
import sys first, _, text = sys.stdin.read().partition("\n")w = int(first)pieces = []for word in text.split():  # 빈칸·탭·줄 바꿈이 몇 개든 한 번에 나눈다    for i in range(0, len(word), w):  # 긴 단어는 w글자씩 자른다(슬라이스는 끝을 넘어도 괜찮다)        pieces.append(word[i:i + w]) lines, line, length = [], [], 0for p in pieces:    if line and length + 1 + len(p) > w:  # 빈칸 하나 + 조각이 w를 넘으면 새 줄        lines.append(" ".join(line))        line, length = [], 0    length += len(p) + (1 if line else 0)    line.append(p)lines.append(" ".join(line))print("\n".join(lines))
JavaScriptmain.js · 22 行
const input = require("fs").readFileSync(0, "utf8");const nl = input.indexOf("\n");const w = Number(input.slice(0, nl));const words = input.slice(nl + 1).trim().split(/\s+/);const pieces = [];for (const word of words)  for (let i = 0; i < word.length; i += w) pieces.push(word.slice(i, i + w)); // slice는 끝을 넘어도 괜찮다 const lines = [];let line = [];let length = 0;for (const p of pieces) {  if (line.length > 0 && length + 1 + p.length > w) {    lines.push(line.join(" "));    line = [];    length = 0;  }  length += p.length + (line.length > 0 ? 1 : 0);  line.push(p);}lines.push(line.join(" "));console.log(lines.join("\n"));
TypeScriptmain.ts · 23 行
import { readFileSync } from "node:fs";const input: string = readFileSync(0, "utf8");const nl: number = input.indexOf("\n");const w: number = Number(input.slice(0, nl));const words: string[] = input.slice(nl + 1).trim().split(/\s+/);const pieces: string[] = [];for (const word of words)  for (let i = 0; i < word.length; i += w) pieces.push(word.slice(i, i + w)); // slice는 끝을 넘어도 괜찮다 const lines: string[] = [];let line: string[] = [];let length = 0;for (const p of pieces) {  if (line.length > 0 && length + 1 + p.length > w) {    lines.push(line.join(" "));    line = [];    length = 0;  }  length += p.length + (line.length > 0 ? 1 : 0);  line.push(p);}lines.push(line.join(" "));console.log(lines.join("\n"));
JavaMain.java · 35 行
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.ArrayList;import java.util.List; public class Main {    public static void main(String[] args) throws IOException {        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));        int w = Integer.parseInt(in.readLine().trim());        List<String> pieces = new ArrayList<>();        String row;        while ((row = in.readLine()) != null) {            for (String word : row.trim().split("\\s+")) {                if (word.isEmpty()) continue; // 빈 줄을 나누면 "" 하나가 나온다                for (int i = 0; i < word.length(); i += w)                    pieces.add(word.substring(i, Math.min(i + w, word.length()))); // 끝을 넘으면 예외            }        }        StringBuilder out = new StringBuilder();        List<String> line = new ArrayList<>();        int length = 0;        for (String p : pieces) {            if (!line.isEmpty() && length + 1 + p.length() > w) {                out.append(String.join(" ", line)).append('\n');                line.clear();                length = 0;            }            length += p.length() + (line.isEmpty() ? 0 : 1);            line.add(p);        }        out.append(String.join(" ", line)).append('\n');        System.out.print(out);    }}
C#Main.cs · 35 行
using System;using System.Collections.Generic;using System.Text; class Program{    static void Main()    {        int w = int.Parse(Console.ReadLine());        var pieces = new List<string>();        string row;        while ((row = Console.ReadLine()) != null)        {            foreach (string word in row.Split((char[])null, StringSplitOptions.RemoveEmptyEntries))                for (int i = 0; i < word.Length; i += w)                    pieces.Add(word.Substring(i, Math.Min(w, word.Length - i))); // 끝을 넘으면 예외        }        var sb = new StringBuilder();        var line = new List<string>();        int length = 0;        foreach (string p in pieces)        {            if (line.Count > 0 && length + 1 + p.Length > w)            {                sb.Append(string.Join(" ", line)).Append('\n');                line.Clear();                length = 0;            }            length += p.Length + (line.Count > 0 ? 1 : 0);            line.Add(p);        }        sb.Append(string.Join(" ", line)).Append('\n');        Console.Write(sb);    }}
C++main.cpp · 24 行
#include <algorithm>#include <iostream>#include <string>#include <vector> int main() {    std::size_t w;    std::cin >> w;    std::vector<std::string> pieces;    std::string word;    while (std::cin >> word) // >>는 공백을 건너뛰고 한 단어씩, 입력이 끝나면 거짓        for (std::size_t i = 0; i < word.size(); i += w) pieces.push_back(word.substr(i, w)); // substr는 끝에서 멈춘다     std::string out, line;    for (const auto& p : pieces) {        if (!line.empty() && line.size() + 1 + p.size() > w) {            out += line + '\n';            line.clear();        }        line += (line.empty() ? "" : " ") + p;    }    out += line + '\n';    std::cout << out;}
Cmain.c · 26 行
#include <stdio.h>#include <string.h> int main(void) {    int w, length = 0; /* length: 지금 줄에 쓴 글자 수(0이면 빈 줄) */    static char word[20001];    scanf("%d", &w);    while (scanf("%20000s", word) == 1) { /* %s는 공백을 건너뛰고 한 단어씩 읽는다 */        int len = (int)strlen(word);        for (int i = 0; i < len; i += w) {            int k = len - i < w ? len - i : w; /* 이 조각의 길이 */            if (length > 0 && length + 1 + k > w) {                putchar('\n');                length = 0;            }            if (length > 0) {                putchar(' ');                length++;            }            fwrite(word + i, 1, k, stdout);            length += k;        }    }    putchar('\n');    return 0;}
Craykonmain.cray · 33 行
w = コンソール.行読み().数に();pieces = [];row = コンソール.行読み();間 (row != なし){    それぞれ (word の中 row.分ける())    {        // 긴 단어는 w글자씩. 부분문자열은 끝을 넘으면 오류라서 남은 길이와 작은 쪽을 쓴다        繰り返す (i = 0; i < word.長さ; i += w)        {            pieces.追加(word.切り出す(i, 数学.小さい方(w, word.長さ - i)));        }    }    row = コンソール.行読み();}line = [];length = 0;それぞれ (p の中 pieces){    もし (line.個数 > 0 && length + 1 + p.長さ > w)    {        コンソール.書く(line.つなぐ(" "));        line = [];        length = 0;    }    もし (line.個数 > 0)    {        length += 1;    }    length += p.長さ;    line.追加(p);}コンソール.書く(line.つなぐ(" "));