はじめに
Java研修コーディング問題集の第6回は 文字列操作(String) です。
Javaでは文字列操作は最も頻繁に行う処理の一つです。Stringクラスの主要メソッドを使いこなせるようにしましょう。
難易度の見方
| マーク | 難易度 | 目安 |
|---|---|---|
| ⭐ | 基本 | 研修1週目レベル |
| ⭐⭐ | 応用 | 少し考える必要あり |
| ⭐⭐⭐ | チャレンジ | 複数の知識を組み合わせる |
問題1:文字列の基本操作 ⭐
問題
文字列 "Hello, Java World!" に対して以下の操作を行い、結果を出力してください。
- 文字列の長さ
- 大文字に変換
- 小文字に変換
- 7文字目以降を取得(
substring) - 先頭の文字を取得(
charAt)
期待する出力
元の文字列: Hello, Java World!
長さ: 18
大文字: HELLO, JAVA WORLD!
小文字: hello, java world!
7文字目以降: Java World!
先頭の文字: H
模範解答
public class Exercise01 {
public static void main(String[] args) {
String str = "Hello, Java World!";
System.out.println("元の文字列: " + str);
System.out.println("長さ: " + str.length());
System.out.println("大文字: " + str.toUpperCase());
System.out.println("小文字: " + str.toLowerCase());
System.out.println("7文字目以降: " + str.substring(7));
System.out.println("先頭の文字: " + str.charAt(0));
}
}
ポイント: Stringは**イミュータブル(不変)**です。toUpperCase() などのメソッドは元の文字列を変更せず、新しい文字列を返します。インデックスは 0始まり です。
問題2:文字列の比較 ⭐
問題
以下の文字列比較の結果を予想してから、実際に実行して確認してください。
String s1 = "Hello";
String s2 = "Hello";
String s3 = new String("Hello");
String s4 = "hello";
比較内容:
s1 == s2s1 == s3s1.equals(s3)s1.equals(s4)s1.equalsIgnoreCase(s4)
期待する出力
s1 == s2 : true
s1 == s3 : false
s1.equals(s3) : true
s1.equals(s4) : false
s1.equalsIgnoreCase(s4) : true
模範解答
public class Exercise02 {
public static void main(String[] args) {
String s1 = "Hello";
String s2 = "Hello";
String s3 = new String("Hello");
String s4 = "hello";
System.out.println("s1 == s2 : " + (s1 == s2));
System.out.println("s1 == s3 : " + (s1 == s3));
System.out.println("s1.equals(s3) : " + s1.equals(s3));
System.out.println("s1.equals(s4) : " + s1.equals(s4));
System.out.println("s1.equalsIgnoreCase(s4) : " + s1.equalsIgnoreCase(s4));
}
}
ポイント: == は参照(アドレス)の比較、.equals() は内容の比較です。文字列リテラル同士は文字列プール(String Pool)で共有されるため s1 == s2 は true ですが、new String() で作成すると別オブジェクトになります。文字列の内容比較には必ず .equals() を使いましょう。
問題3:文字列の検索と判定 ⭐
問題
文字列 "Java Programming Language" に対して以下の検索・判定を行ってください。
期待する出力
元の文字列: Java Programming Language
"Program" を含む: true
"python" を含む: false
"Java" で始まる: true
"Language" で終わる: true
"gram" の位置: 10
空白の位置(最初): 4
空白の位置(最後): 16
模範解答
public class Exercise03 {
public static void main(String[] args) {
String str = "Java Programming Language";
System.out.println("元の文字列: " + str);
System.out.println("\"Program\" を含む: " + str.contains("Program"));
System.out.println("\"python\" を含む: " + str.contains("python"));
System.out.println("\"Java\" で始まる: " + str.startsWith("Java"));
System.out.println("\"Language\" で終わる: " + str.endsWith("Language"));
System.out.println("\"gram\" の位置: " + str.indexOf("gram"));
System.out.println("空白の位置(最初): " + str.indexOf(" "));
System.out.println("空白の位置(最後): " + str.lastIndexOf(" "));
}
}
ポイント: contains() は大文字小文字を区別します。indexOf() は見つからない場合に -1 を返します。これらのメソッドは入力値のバリデーションや文字列解析で頻繁に使います。
問題4:文字列の分割と結合 ⭐⭐
問題
CSV形式の文字列 "田中,25,東京,エンジニア" を分割して整形し、再度別の区切り文字で結合してください。
期待する出力
=== CSV解析 ===
元のデータ: 田中,25,東京,エンジニア
---
名前: 田中
年齢: 25
住所: 東京
職業: エンジニア
---
タブ区切り: 田中 25 東京 エンジニア
パイプ区切り: 田中 | 25 | 東京 | エンジニア
模範解答
public class Exercise04 {
public static void main(String[] args) {
String csv = "田中,25,東京,エンジニア";
System.out.println("=== CSV解析 ===");
System.out.println("元のデータ: " + csv);
System.out.println("---");
String[] parts = csv.split(",");
String[] labels = {"名前", "年齢", "住所", "職業"};
for (int i = 0; i < parts.length; i++) {
System.out.println(labels[i] + ": " + parts[i]);
}
System.out.println("---");
System.out.println("タブ区切り: " + String.join("\t", parts));
System.out.println("パイプ区切り: " + String.join(" | ", parts));
}
}
ポイント: split() は正規表現で文字列を分割し配列を返します。String.join() は区切り文字で配列を結合します。CSV解析は実務でよく行う処理です。split("\\.") のように正規表現の特殊文字はエスケープが必要です。
問題5:文字列の置換とトリム ⭐⭐
問題
以下の文字列を処理してください。
-
" Hello, World! "→ 前後の空白を除去(trim) -
"2024-01-15"→/区切りに変換 -
"I like Java. Java is great. Java!"→"Java"を"Python"に全置換 -
"abc123def456"→ 数字をすべて除去(正規表現)
期待する出力
1. trim: [Hello, World!]
2. 区切り変換: 2024/01/15
3. 全置換: I like Python. Python is great. Python!
4. 数字除去: abcdef
模範解答
public class Exercise05 {
public static void main(String[] args) {
// 1. trim
String padded = " Hello, World! ";
System.out.println("1. trim: [" + padded.trim() + "]");
// 2. 区切り変換
String date = "2024-01-15";
System.out.println("2. 区切り変換: " + date.replace("-", "/"));
// 3. 全置換
String sentence = "I like Java. Java is great. Java!";
System.out.println("3. 全置換: " + sentence.replace("Java", "Python"));
// 4. 数字除去(正規表現)
String mixed = "abc123def456";
System.out.println("4. 数字除去: " + mixed.replaceAll("[0-9]", ""));
}
}
ポイント: replace() はリテラル文字列の置換、replaceAll() は正規表現での置換です。trim() は前後の空白のみ除去し、途中の空白はそのままです。Java 11以降では strip() メソッドも利用できます。
問題6:文字列の逆転 ⭐⭐
問題
文字列を逆順にするメソッドを2つの方法で実装してください。
- ループを使う方法
-
StringBuilderを使う方法
文字列 "Java Programming" を逆転させてください。
期待する出力
元の文字列: Java Programming
方法1(ループ): gnimmargorP avaJ
方法2(StringBuilder): gnimmargorP avaJ
模範解答
public class Exercise06 {
public static void main(String[] args) {
String str = "Java Programming";
System.out.println("元の文字列: " + str);
System.out.println("方法1(ループ): " + reverseByLoop(str));
System.out.println("方法2(StringBuilder): " + reverseByBuilder(str));
}
static String reverseByLoop(String str) {
String result = "";
for (int i = str.length() - 1; i >= 0; i--) {
result += str.charAt(i);
}
return result;
}
static String reverseByBuilder(String str) {
return new StringBuilder(str).reverse().toString();
}
}
ポイント: ループ版は += で文字列を結合するたびに新しいStringオブジェクトが作られるため効率が悪いです。StringBuilder は内部バッファを変更するため高速です。実務では StringBuilder を使いましょう。
問題7:回文チェック ⭐⭐
問題
入力された文字列が回文(前から読んでも後ろから読んでも同じ)かどうかを判定するメソッドを作成してください。大文字小文字は区別しないものとします。
期待する出力
"level" → 回文です
"Java" → 回文ではありません
"Madam" → 回文です
"racecar" → 回文です
"12321" → 回文です
模範解答
public class Exercise07 {
public static void main(String[] args) {
String[] words = {"level", "Java", "Madam", "racecar", "12321"};
for (String word : words) {
String result = isPalindrome(word) ? "回文です" : "回文ではありません";
System.out.println("\"" + word + "\" → " + result);
}
}
static boolean isPalindrome(String str) {
String lower = str.toLowerCase();
int left = 0;
int right = lower.length() - 1;
while (left < right) {
if (lower.charAt(left) != lower.charAt(right)) {
return false;
}
left++;
right--;
}
return true;
}
}
ポイント: 両端から中央に向かって比較する ツーポインタ法 を使っています。先頭と末尾から1文字ずつ比較し、すべて一致すれば回文です。大文字小文字を無視するために toLowerCase() で統一しています。
問題8:文字の出現回数カウント ⭐⭐
問題
文字列 "programming" に含まれる各文字の出現回数をカウントして、出現回数順(多い順)に出力してください。
期待する出力
文字列: programming
--- 出現回数 ---
g: 2回
r: 2回
m: 2回
p: 1回
o: 1回
a: 1回
i: 1回
n: 1回
模範解答
public class Exercise08 {
public static void main(String[] args) {
String str = "programming";
System.out.println("文字列: " + str);
System.out.println("--- 出現回数 ---");
// 出現する文字を記録(重複なし)
String checked = "";
// 文字と回数を配列で管理
char[] chars = new char[str.length()];
int[] counts = new int[str.length()];
int uniqueCount = 0;
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (checked.indexOf(c) == -1) {
chars[uniqueCount] = c;
int count = 0;
for (int j = 0; j < str.length(); j++) {
if (str.charAt(j) == c) count++;
}
counts[uniqueCount] = count;
uniqueCount++;
checked += c;
}
}
// 出現回数順にソート(バブルソート)
for (int i = 0; i < uniqueCount - 1; i++) {
for (int j = 0; j < uniqueCount - 1 - i; j++) {
if (counts[j] < counts[j + 1]) {
int tmpCount = counts[j];
counts[j] = counts[j + 1];
counts[j + 1] = tmpCount;
char tmpChar = chars[j];
chars[j] = chars[j + 1];
chars[j + 1] = tmpChar;
}
}
}
for (int i = 0; i < uniqueCount; i++) {
System.out.println(chars[i] + ": " + counts[i] + "回");
}
}
}
ポイント: 配列だけで文字の出現回数を管理しています。後の回で学ぶ HashMap を使えばもっと簡潔に書けますが、ここではデータ構造の基礎を学ぶため配列で実装しています。
問題9:簡易テンプレートエンジン ⭐⭐⭐
問題
テンプレート文字列中の {変数名} を実際の値に置換する簡易テンプレートエンジンを作成してください。
期待する出力
=== テンプレート ===
{name}様
いつもご利用ありがとうございます。
{date}付けで{product}のご注文を承りました。
合計金額は{price}円です。
=== 変換後 ===
田中太郎様
いつもご利用ありがとうございます。
2024年4月1日付けでノートPCのご注文を承りました。
合計金額は98000円です。
模範解答
public class Exercise09 {
public static void main(String[] args) {
String template = "{name}様\n\n"
+ "いつもご利用ありがとうございます。\n"
+ "{date}付けで{product}のご注文を承りました。\n"
+ "合計金額は{price}円です。";
String[] keys = {"name", "date", "product", "price"};
String[] values = {"田中太郎", "2024年4月1日", "ノートPC", "98000"};
System.out.println("=== テンプレート ===");
System.out.println(template);
String result = applyTemplate(template, keys, values);
System.out.println("\n=== 変換後 ===");
System.out.println(result);
}
static String applyTemplate(String template, String[] keys, String[] values) {
String result = template;
for (int i = 0; i < keys.length; i++) {
result = result.replace("{" + keys[i] + "}", values[i]);
}
return result;
}
}
ポイント: テンプレートエンジンはWebアプリケーションやメール送信でよく使われるパターンです。replace() はすべての一致箇所を置換します。実務では Thymeleaf などのテンプレートエンジンを使いますが、基本的な考え方は同じです。
問題10:パスワード強度チェッカー ⭐⭐⭐
問題
パスワードの強度を判定するメソッドを作成してください。
判定基準:
- 8文字以上か
- 大文字を含むか
- 小文字を含むか
- 数字を含むか
- 特殊文字(
!@#$%^&*)を含むか
強度レベル:
- 5つすべて満たす → 「非常に強い」
- 4つ満たす → 「強い」
- 3つ満たす → 「普通」
- 2つ以下 → 「弱い」
期待する出力
=== パスワード強度チェック ===
"abc" → 弱い(1/5)
[ ] 8文字以上 [✓] 小文字 [ ] 大文字 [ ] 数字 [ ] 特殊文字
"password" → 弱い(2/5)
[✓] 8文字以上 [✓] 小文字 [ ] 大文字 [ ] 数字 [ ] 特殊文字
"Pass1234" → 強い(4/5)
[✓] 8文字以上 [✓] 小文字 [✓] 大文字 [✓] 数字 [ ] 特殊文字
"P@ss1234!" → 非常に強い(5/5)
[✓] 8文字以上 [✓] 小文字 [✓] 大文字 [✓] 数字 [✓] 特殊文字
模範解答
public class Exercise10 {
public static void main(String[] args) {
String[] passwords = {"abc", "password", "Pass1234", "P@ss1234!"};
System.out.println("=== パスワード強度チェック ===");
for (String pw : passwords) {
checkPassword(pw);
System.out.println();
}
}
static void checkPassword(String password) {
boolean hasLength = password.length() >= 8;
boolean hasLower = false;
boolean hasUpper = false;
boolean hasDigit = false;
boolean hasSpecial = false;
String specialChars = "!@#$%^&*";
for (int i = 0; i < password.length(); i++) {
char c = password.charAt(i);
if (Character.isLowerCase(c)) hasLower = true;
if (Character.isUpperCase(c)) hasUpper = true;
if (Character.isDigit(c)) hasDigit = true;
if (specialChars.indexOf(c) >= 0) hasSpecial = true;
}
int score = 0;
if (hasLength) score++;
if (hasLower) score++;
if (hasUpper) score++;
if (hasDigit) score++;
if (hasSpecial) score++;
String level;
if (score >= 5) {
level = "非常に強い";
} else if (score >= 4) {
level = "強い";
} else if (score >= 3) {
level = "普通";
} else {
level = "弱い";
}
System.out.println("\"" + password + "\" → " + level + "(" + score + "/5)");
System.out.println(" " +
mark(hasLength) + " 8文字以上 " +
mark(hasLower) + " 小文字 " +
mark(hasUpper) + " 大文字 " +
mark(hasDigit) + " 数字 " +
mark(hasSpecial) + " 特殊文字");
}
static String mark(boolean condition) {
return condition ? "[✓]" : "[ ]";
}
}
ポイント: Character.isLowerCase(), Character.isUpperCase(), Character.isDigit() などのCharacterクラスのメソッドは文字の判定に便利です。パスワード検証は実務でもよくある処理で、セキュリティの基本です。
まとめ
| 問題 | テーマ | 難易度 |
|---|---|---|
| 問題1 | 文字列の基本操作 | ⭐ |
| 問題2 | 文字列の比較(==とequals) | ⭐ |
| 問題3 | 文字列の検索と判定 | ⭐ |
| 問題4 | 分割と結合(split / join) | ⭐⭐ |
| 問題5 | 置換とトリム | ⭐⭐ |
| 問題6 | 文字列の逆転 | ⭐⭐ |
| 問題7 | 回文チェック | ⭐⭐ |
| 問題8 | 文字の出現回数カウント | ⭐⭐ |
| 問題9 | 簡易テンプレートエンジン | ⭐⭐⭐ |
| 問題10 | パスワード強度チェッカー | ⭐⭐⭐ |
次回は クラスとオブジェクト のコーディング問題です!
シリーズ一覧:Java研修コーディング問題集
- 変数・データ型・演算子 編
- 条件分岐(if / switch)編
- 繰り返し処理(for / while)編
- 配列 編
- メソッド 編
- 👉 文字列操作(String)編(本記事)
- クラスとオブジェクト 編
- 継承とインターフェース 編
- 例外処理 編
- コレクションと Stream API 編
著者: @kotaro_ai_lab
AI駆動開発やテック情報を毎日発信しています。フォローお気軽にどうぞ!