データ · 12
文字列の組み立て
かけらをつないで文字列を作る、区切りを入れてつなぐ、1行に並べて表示する。
出力する文字列を一度に書けないときは、かけらを一つずつ足して作ります。
下の例は単語を読み込み、頭文字だけを集めた文字列、単語をカンマでつないだ文字列、単語の長さを空白で並べた1行を順に表示します。
words = input().split()initials = ""for w in words: initials += w[0] # 한 조각씩 붙여 가요print(initials)print(", ".join(words)) # 사이에만 ", "lens = [len(w) for w in words]print(*lens) # 빈칸으로 이어 찍기const words = require("fs").readFileSync(0, "utf8").trim().split(/\s+/);let initials = "";for (const w of words) { initials += w[0]; // 한 조각씩 붙여 가요}console.log(initials);console.log(words.join(", ")); // 사이에만 ", "const lens = words.map((w) => w.length);console.log(lens.join(" ")); // 빈칸으로 이어 찍기import { readFileSync } from "node:fs";const words: string[] = readFileSync(0, "utf8").trim().split(/\s+/);let initials: string = "";for (const w of words) { initials += w[0]; // 한 조각씩 붙여 가요}console.log(initials);console.log(words.join(", ")); // 사이에만 ", "const lens: number[] = words.map((w) => w.length);console.log(lens.join(" ")); // 빈칸으로 이어 찍기import java.util.Scanner; public class Main { public static void main(String[] args) { String[] words = new Scanner(System.in).nextLine().trim().split(" +"); StringBuilder initials = new StringBuilder(); for (String w : words) { initials.append(w.charAt(0)); // 한 조각씩 붙여 가요 } System.out.println(initials); System.out.println(String.join(", ", words)); // 사이에만 ", " int[] lens = new int[words.length]; for (int i = 0; i < words.length; i++) lens[i] = words[i].length(); for (int i = 0; i < lens.length; i++) { if (i > 0) System.out.print(" "); // 첫 값 앞에는 안 찍어요 System.out.print(lens[i]); } System.out.println(); }}using System;using System.Text; class Program{ static void Main() { string[] words = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries); var initials = new StringBuilder(); foreach (string w in words) { initials.Append(w[0]); // 한 조각씩 붙여 가요 } Console.WriteLine(initials); Console.WriteLine(string.Join(", ", words)); // 사이에만 ", " int[] lens = new int[words.Length]; for (int i = 0; i < words.Length; i++) lens[i] = words[i].Length; Console.WriteLine(string.Join(" ", lens)); // 빈칸으로 이어 찍기 }}#include <iostream>#include <string>#include <vector> int main() { std::vector<std::string> words; std::string w; while (std::cin >> w) words.push_back(w); std::string initials; for (const std::string& x : words) { initials += x[0]; // 한 조각씩 붙여 가요 } std::cout << initials << '\n'; for (size_t i = 0; i < words.size(); i++) { if (i > 0) std::cout << ", "; // 사이에만 ", " std::cout << words[i]; } std::cout << '\n'; std::vector<int> lens; for (const std::string& x : words) lens.push_back(x.size()); for (size_t i = 0; i < lens.size(); i++) { if (i > 0) std::cout << ' '; // 첫 값 앞에는 안 찍어요 std::cout << lens[i]; } std::cout << '\n';}#include <stdio.h>#include <string.h> int main(void) { char words[100][51], initials[101]; int n = 0, lens[100]; while (n < 100 && scanf("%50s", words[n]) == 1) n++; for (int i = 0; i < n; i++) { initials[i] = words[i][0]; // 한 조각씩 붙여 가요 } initials[n] = '\0'; // 문자열의 끝 표시 printf("%s\n", initials); for (int i = 0; i < n; i++) { if (i > 0) printf(", "); // 사이에만 ", " printf("%s", words[i]); } printf("\n"); for (int i = 0; i < n; i++) lens[i] = strlen(words[i]); for (int i = 0; i < n; i++) { if (i > 0) printf(" "); // 첫 값 앞에는 안 찍어요 printf("%d", lens[i]); } printf("\n"); return 0;}words = コンソール.行読み().分ける();initials = "";それぞれ (w の中 words){ initials += w[0]; // 한 조각씩 붙여 가요}コンソール.書く(initials);コンソール.書く(words.つなぐ(", ")); // 사이에만 ", "lens = [];それぞれ (w の中 words){ lens.追加(w.長さ);}コンソール.書く(lens); // 목록은 빈칸으로 이어 찍어요red green blue
rgb red, green, blue 3 5 4
ポイント
- 組み立て:空の文字列から始めて、繰り返しながら後ろにかけらを足します(
initials += w[0])。
合計をtotal += xで集めたのと同じ形です。 - Java と C# の
+=は、足すたびにそれまでの文字列を丸ごと新しく作ります。
そこで、かけらをためておいて最後に一度だけ文字列にする StringBuilder が別にあります。 - 数を足すとき、自動で文字列に変えてくれる言語と、自分で変えてから足す言語があります。
- 連結(join)はリストの値のあいだにだけ区切りの文字列を入れて一つにします。
red、green、blueを", "でつなぐとred, green, blueです。
最後には付きません。 - 連結のない言語ではループで書きます。
最初の値でないときだけ先に区切りを表示してから値を表示すれば、最後に区切りが残りません。 - 数をいくつか1行に表示するのも同じ仕事です。
まとめて表示する短い書き方がある言語もあれば、改行しない出力で一つずつ表示する言語もあります。
言語ごとの書き方
| Python | 足すのは s += かけら — 数は str(n) で変えてから足します。かけらが多いときはリストに append して最後に "".join(parts)。", ".join(words) は文字列のリストしか受け取りません。1行出力は print(*nums)、区切りを変えるなら print(*nums, sep=", ") |
|---|---|
| JavaScript | 足すのは s += かけら — 数も自動で文字列になります。words.join(", ") は数の配列でも使え、かっこを空にした join() はカンマでつなぎます。1行出力は console.log(nums.join(" ")) |
| TypeScript | JavaScript と同じです |
| Java | StringBuilder sb = new StringBuilder(); のあと sb.append(かけら) — 文字・数・文字列のどれも受け取ります。最後に sb.toString() で変えるか、そのまま println(sb)。String.join(", ", words) は文字列しか受け取りません。数は System.out.print で一つずつ表示するか、StringBuilder にためます |
| C# | var sb = new StringBuilder();(using System.Text;)のあと sb.Append(かけら)、最後に sb.ToString()。string.Join(", ", words) は数の配列も受け取るので、1行出力は Console.WriteLine(string.Join(" ", nums)) です |
| C++ | std::string は書き換えられるので、s += かけら はその場で足されます。数は std::to_string(n) で変えてから足します。連結がないので if (i > 0) std::cout << ", "; のようにループで書きます。std::ostringstream に << でためて .str() で取り出すこともできます |
| C | 文字列は char の配列なので、場所を多めに取り、1文字ずつ入れて最後に '\0' を入れます。文字列を足すのは strcat(buf, "cd")、数は sprintf(buf + len, "%d", n)。連結がないのでループと printf で書きます |
| Craykon | 足すのは s += かけら — 数も自動で文字列になります。words.つなぐ(", ") は数のリストでも使えます。コンソール.書く(リスト) は空白で並べて表示し、一つずつ表示するときは改行しない コンソール.続けて書く(値) |
よくある間違い
区切りを値の後ろに付けた
words = ["red", "green", "blue"]
line = ""
for w in words:
line += w + ","
print(line)→ red,green,blue, — 最後にカンマが一つ余分に付きます
連結を使うか、最初の値でないときだけ値の前に付けます:if line: line += "," のあとに line += w。
引用符の文字列二つを + でつないだC · C++
char *s = "ab" + "cd";→ コンパイルエラー invalid operands to binary + — C の文字列はアドレスなので足せません。C++ の std::string s = "ab" + "cd"; も同じ理由でコンパイルエラーです
C は char buf[10] = "ab"; strcat(buf, "cd");、C++ は片方を std::string にします:std::string("ab") + "cd"。
数のリストをそのままつないだPython · Java
print(", ".join([1, 2, 3]))→ Python は TypeError: sequence item 0: expected str instance, int found。Java も int[] nums に String.join(", ", nums) を使うとコンパイルエラーです
Python は ", ".join(map(str, nums)) か print(*nums, sep=", ")、Java は StringBuilder にためます。
JavaScript・C#・Craykon の連結は数も受け取ります。
言語ごとの違い
かけらが多いときは、足し方によって時間が大きく変わります。
このサイトの採点と同じ環境で1文字ずつ 20 万回足してみると、Java は
Python も、例のように関数の外で
JavaScript(Node.js)は
計った時間はコンピュータによって変わります。
また、C++ で数を足すときは必ず
かけらが多いときは、足し方によって時間が大きく変わります。
このサイトの採点と同じ環境で1文字ずつ 20 万回足してみると、Java は
+= で 1 秒ほど、StringBuilder で 1〜2ms、C# は += で 2〜3 秒、StringBuilder で 1〜2ms でした。Python も、例のように関数の外で
+= で足すと 0.5 秒ほど、リストにためて join すると 10ms かかりませんでした。JavaScript(Node.js)は
+= でも 10ms 前後でした。計った時間はコンピュータによって変わります。
また、C++ で数を足すときは必ず
std::to_string を通します。s += 65 は "65" ではなく、コード 65 の文字 A を足します。