0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

オブジェクト指向って何?RPGで理解する超入門 Part2 (文字列処理でデータを整形しよう!)

0
Last updated at Posted at 2026-02-08

part2_episode05_title_banner.png

学習時間: 約35分
難易度: ★★☆☆☆

この回で学ぶこと

この回では、文字列処理を学びます!

プレイヤー情報やバトルログを美しく表示するために、Javaの文字列処理機能を使いこなしましょう。

学習内容

  • String.format() - データを美しく整形
  • StringBuilder - 効率的な文字列結合
  • split() / join() - データの分割と結合

📁 成果物のファイル構成

今回作成するファイル構成です。

rpg_string_system/
├── src/
│   ├── com/javaquest/
│   │   ├── RPGSystem.java          # メインクラス(デモ実行)
│   │   ├── model/
│   │   │   └── Player.java         # プレイヤーモデル
│   │   └── logger/
│   │       └── BattleLogger.java   # バトルログシステム
│   └── practice/
│       ├── ItemFormatter.java      # 練習問題1
│       └── SkillDescriptionGenerator.java # 練習問題2
└── README.md                       # このファイル

実装するもの

  • プレイヤー情報フォーマッター
  • バトルログシステム
  • パーティ一覧表示

📚GitHub:成果物のサンプルはこちら

基礎知識

文字列処理が必要な理由

RPGゲームでは、プレイヤー情報やバトルログなど、たくさんの文字列を扱います。

❌ 読みにくい表示
勇者レベル15HP120MP80

✅ 美しい表示
[勇者] Lv.15  HP: 120/150 (80%)  MP: 80/100 (80%)

String.format() とは?

String.format() は、データを指定した形式で整形する機能です。

string_format_showcase.png

// 基本的な使い方
String name = "勇者";
int level = 15;

// %s = 文字列、%d = 整数
String message = String.format("[%s] Lv.%d", name, level);
System.out.println(message);  // [勇者] Lv.15

フォーマット指定子一覧

指定子 意味 結果
%s 文字列 String.format("名前: %s", "勇者") 名前: 勇者
%d 整数 String.format("Lv.%d", 15) Lv.15
%f 小数 String.format("%.2f", 3.14159) 3.14
%3d 3桁整数 String.format("HP:%3d", 80) HP: 80
%-10s 左寄せ10文字 String.format("%-10s", "勇者") 勇者

StringBuilder とは?

StringBuilder は、文字列を効率的に結合するためのクラスです。

stringbuilder_mechanism.png

// ❌ 非効率な方法(Stringの連結)
String log = "";
log = log + "[ターン1] ";
log = log + "勇者の攻撃! ";
log = log + "スライムに10ダメージ!";

// ✅ 効率的な方法(StringBuilder)
StringBuilder sb = new StringBuilder();
sb.append("[ターン1] ");
sb.append("勇者の攻撃! ");
sb.append("スライムに10ダメージ!");
String log = sb.toString();

String vs StringBuilder

string_vs_stringbuilder.png

特徴 String StringBuilder
変更可能? 不可(immutable) 可能(mutable)
連結速度 遅い 速い
メモリ効率 非効率 効率的
用途 固定文字列 動的文字列生成

実装演習

ステップ1: Player クラス(復習)

まずは、プレイヤークラスを準備します。

ファイルrpg_string_system/model/Player.java

Player.java
package model;

public class Player {
    private String name;
    private String job;
    private int level;
    private int hp;
    private int maxHp;

    public Player(String name, String job, int level) {
        this.name = name;
        this.job = job;
        this.level = level;
        this.maxHp = 100 + (level * 10);
        this.hp = this.maxHp;
    }

    // ゲッター
    public String getName() { return name; }
    public String getJob() { return job; }
    public int getLevel() { return level; }
    public int getHp() { return hp; }
    public int getMaxHp() { return maxHp; }

    // ダメージを受ける
    public void takeDamage(int damage) {
        this.hp = Math.max(0, this.hp - damage);
    }

    // HP割合を計算
    public double getHpPercentage() {
        return (double) hp / maxHp * 100;
    }

    // HPバーを作成
    public String getHpBar(int length) {
        int filled = (int) ((double) hp / maxHp * length);
        StringBuilder bar = new StringBuilder();
        for (int i = 0; i < length; i++) {
            bar.append(i < filled ? "■" : "□");
        }
        return bar.toString();
    }
}

ステップ2: BattleLogger - バトルログシステム

バトルの様子をログとして記録するクラスを作成します。

ファイルrpg_string_system/logger/BattleLogger.java

BattleLogger.java
package logger;

import java.util.ArrayList;
import java.util.List;

public class BattleLogger {
    private List<String> logs;
    private int turnCount;

    public BattleLogger() {
        this.logs = new ArrayList<>();
        this.turnCount = 0;
    }

    /**
     * ターン開始
     */
    public void startTurn() {
        turnCount++;
        logs.add(String.format("【ターン %d】", turnCount));
    }

    /**
     * 攻撃ログを追加
     */
    public void logAttack(String attacker, String target, int damage) {
        String log = String.format("  %s の攻撃! %s に %d ダメージ!", 
            attacker, target, damage);
        logs.add(log);
    }

    /**
     * スキル使用ログを追加
     */
    public void logSkill(String user, String skillName, String target, int damage) {
        String log = String.format("  %s は %s を使った! %s に %d ダメージ!", 
            user, skillName, target, damage);
        logs.add(log);
    }

    /**
     * 勝利ログを追加
     */
    public void logVictory(int exp, int gold) {
        logs.add("─────────────────────");
        logs.add("勝利!");
        logs.add(String.format("  経験値 +%d", exp));
        logs.add(String.format("  ゴールド +%d", gold));
    }

    /**
     * すべてのログを表示
     */
    public void printAll() {
        System.out.println("\n=== バトルログ ===");
        for (String log : logs) {
            System.out.println(log);
        }
        System.out.println("==================\n");
    }
}

ステップ3: RPGSystem - メインシステム

すべての機能を統合して実行するメインクラスです。

ファイルrpg_string_system/RPGSystem.java

RPGSystem.java
import logger.BattleLogger;
import model.Player;

public class RPGSystem {
    public static void main(String[] args) {

        // Demo 1: String.format() の基本
        demoStringFormat();

        // Demo 2: プレイヤー情報の整形
        demoPlayerFormat();

        // Demo 3: バトルログシステム
        demoBattleLog();

    }

    /**
     * Demo 1: String.format() の基本
     */
    private static void demoStringFormat() {
        System.out.println("=== String.format() デモ ===\n");

        // 基本的な使い方
        String name = "勇者";
        int level = 15;
        System.out.println(String.format("[%s] Lv.%d", name, level));

        // 桁揃え(右寄せ)
        System.out.println(String.format("HP:%3d/%3d", 80, 150));

        // 桁揃え(左寄せ)
        System.out.println(String.format("%-10s: %d", "攻撃力", 50));

        // 小数点制御
        System.out.println(String.format("勝率: %.1f%%", 85.7));

        System.out.println();
    }

    /**
     * Demo 2: プレイヤー情報の整形
     */
    private static void demoPlayerFormat() {
        System.out.println("=== プレイヤー情報フォーマット ===\n");

        Player hero = new Player("アリス", "勇者", 15);
        Player mage = new Player("ボブ", "魔法使い", 12);

        // シンプル表示
        System.out.println("【シンプル表示】");
        System.out.println(formatPlayerSimple(hero));
        System.out.println();

        // 詳細表示
        System.out.println("【詳細表示】");
        System.out.println(formatPlayerDetailed(hero));
        System.out.println(formatPlayerDetailed(mage));
        System.out.println();

    }

    /**
     * Demo 3: バトルログシステム
     */
    private static void demoBattleLog() {
        System.out.println("=== バトルログシステム ===\n");

        Player hero = new Player("アリス", "勇者", 15);
        BattleLogger logger = new BattleLogger();

        // バトルシミュレーション
        logger.startTurn();
        hero.takeDamage(20);
        logger.logAttack("スライム", hero.getName(), 20);

        logger.startTurn();
        logger.logAttack(hero.getName(), "スライム", 35);

        logger.startTurn();
        logger.logSkill(hero.getName(), "剣技・疾風斬", "スライム", 60);

        logger.logVictory(120, 80);
        logger.printAll();
    }

    // === ヘルパーメソッド ===

    /**
     * シンプルなプレイヤー表示
     */
    private static String formatPlayerSimple(Player p) {
        return String.format("[%s] Lv.%d", p.getName(), p.getLevel());
    }

    /**
     * 詳細なプレイヤー表示
     */
    private static String formatPlayerDetailed(Player p) {
        return String.format("[%s] Lv.%2d HP:%3d/%3d (%.0f%%)",
            p.getName(),
            p.getLevel(),
            p.getHp(),
            p.getMaxHp(),
            p.getHpPercentage()
        );
    }

}

実行結果:

=== String.format() デモ ===

[勇者] Lv.15
HP: 80/150
攻撃力       : 50
勝率: 85.7%

=== プレイヤー情報フォーマット ===

【シンプル表示】
[アリス] Lv.15

【詳細表示】
[アリス] Lv.15 HP:250/250 (100%)
[ボブ] Lv.12 HP:220/220 (100%)

=== バトルログシステム ===


=== バトルログ ===
【ターン 1】
  スライム の攻撃! アリス に 20 ダメージ!
【ターン 2】
  アリス の攻撃! スライム に 35 ダメージ!
【ターン 3】
  アリス は 剣技・疾風斬 を使った! スライム に 60 ダメージ!
─────────────────────
勝利!
  経験値 +120
  ゴールド +80
==================

🎓 String.format() の詳細

よく使うフォーマット指定子

// 整数フォーマット
String.format("%d", 123);           // "123"
String.format("%5d", 123);          // "  123" (5桁、右寄せ)
String.format("%-5d", 123);         // "123  " (5桁、左寄せ)
String.format("%05d", 123);         // "00123" (ゼロ埋め)

// 小数フォーマット
String.format("%.2f", 3.14159);     // "3.14" (小数点2桁)
String.format("%8.2f", 3.14);       // "    3.14" (全体8桁、小数2桁)

// 文字列フォーマット
String.format("%s", "勇者");        // "勇者"
String.format("%10s", "勇者");      // "        勇者" (10桁、右寄せ)
String.format("%-10s", "勇者");     // "勇者        " (10桁、左寄せ)

// 複数の値を組み合わせ
String.format("[%s] Lv.%d HP:%d/%d (%.1f%%)", 
    "勇者", 15, 120, 150, 80.0);
// "[勇者] Lv.15 HP:120/150 (80.0%)"

StringBuilder のメソッド一覧

メソッド 説明
append(String) 文字列を追加 sb.append("Hello")
insert(int, String) 指定位置に挿入 sb.insert(0, "Hi ")
delete(int, int) 指定範囲を削除 sb.delete(0, 3)
replace(int, int, String) 置換 sb.replace(0, 2, "Bye")
reverse() 逆順にする sb.reverse()
toString() Stringに変換 sb.toString()
length() 長さを取得 sb.length()
setLength(int) 長さを設定 sb.setLength(0) (クリア)

練習問題

練習1: アイテム情報のフォーマット(基本)

以下のような出力を作ってください。

=== アイテム一覧 ===
[001] ポーション      価格:   50G 効果: HP+50
[002] エリクサー      価格:  500G 効果: HP+MAX
[003] 魔法の杖        価格: 1200G 効果: 魔力+10
ヒント
  • String.format() を使用
  • %03d: 3桁のゼロ埋め整数
  • %-15s: 15文字の左寄せ文字列
  • %5d: 5桁の右寄せ整数
解答例
public class ItemFormatter {
    public static void main(String[] args) {
        System.out.println("=== アイテム一覧 ===");
        
        formatItem(1, "ポーション", 50, "HP+50");
        formatItem(2, "エリクサー", 500, "HP+MAX");
        formatItem(3, "魔法の杖", 1200, "魔力+10");
    }
    
    private static void formatItem(int id, String name, int price, String effect) {
        System.out.println(String.format(
            "[%03d] %-15s 価格: %5dG 効果: %s",
            id, name, price, effect
        ));
    }
}

練習2: スキル説明文の動的生成(応用)

StringBuilderを使って、スキルの説明文を動的に生成してください。

要件:

  • スキル名、消費MP、ダメージ倍率、追加効果を組み合わせる
  • 複数のスキルをHashMapで管理
  • 説明文を自動生成

実行結果:

【ファイア】
  消費MP: 15
  ダメージ: 1.5倍
  効果: 炎属性ダメージ

【ヒール】
  消費MP: 10
  効果: HP50回復

【サンダー】
  消費MP: 20
  ダメージ: 2.0倍
  効果: 雷属性ダメージ、麻痺効果
SkillDescriptionGenerator.java
public class SkillDescriptionGenerator {
    /**
     * Skillクラス
     */
    static class Skill {
        String name;
        int mpCost;
        double damageMultiplier;
        String effect;
        
        Skill(String name, int mpCost, double damageMultiplier, String effect) {
            this.name = name;
            this.mpCost = mpCost;
            this.damageMultiplier = damageMultiplier;
            this.effect = effect;
        }
    }

    /**
     * 実行メソッド
     */
    public static void main(String[] args) {
        // ここに処理を実装する
    }
}
解答例
SkillDescriptionGenerator.java
import java.util.HashMap;
import java.util.Map;

public class SkillDescriptionGenerator {
    static class Skill {
        String name;
        int mpCost;
        double damageMultiplier;
        String effect;
        
        Skill(String name, int mpCost, double damageMultiplier, String effect) {
            this.name = name;
            this.mpCost = mpCost;
            this.damageMultiplier = damageMultiplier;
            this.effect = effect;
        }
    }
    
    public static void main(String[] args) {
        Map<String, Skill> skills = new HashMap<>();
        skills.put("ファイア", new Skill("ファイア", 15, 1.5, "炎属性ダメージ"));
        skills.put("ヒール", new Skill("ヒール", 10, 0.0, "HP50回復"));
        skills.put("サンダー", new Skill("サンダー", 20, 2.0, "雷属性ダメージ、麻痺効果"));
        
        for (Skill skill : skills.values()) {
            System.out.println(generateDescription(skill));
            System.out.println();
        }
    }
    
    private static String generateDescription(Skill skill) {
        StringBuilder sb = new StringBuilder();
        sb.append("【").append(skill.name).append("】\n");
        sb.append(String.format("  消費MP: %d\n", skill.mpCost));
        
        if (skill.damageMultiplier > 0) {
            sb.append(String.format("  ダメージ: %.1f倍\n", skill.damageMultiplier));
        }
        
        sb.append("  効果: ").append(skill.effect);
        
        return sb.toString();
    }
}

まとめ

今回学んだこと

  • String.format() でデータを美しく整形
  • StringBuilder で効率的な文字列結合
  • フォーマット指定子 の使い方
  • パフォーマンス比較 で速度差を実感
  • 実践的な応用 でRPGシステムを構築

重要ポイント

項目 String連結 StringBuilder
速度 🐢 遅い 🚀 速い
用途 固定文字列 動的生成
推奨 数回の連結 大量の連結

次回予告

第6回: CSVファイル - データの入出力

第5回で学んだ文字列処理を活かして、CSVファイルの読み書きに挑戦します!

  • CSVファイルの読み込み
  • データのパース(split活用)
  • CSVファイルへの書き込み
  • プレイヤーデータの永続化

📖 参考資料

公式ドキュメント

学習リソース

パフォーマンス関連

関連記事

Java Quest Part 2 シリーズ

  • 第5回: 文字列処理でデータを整形しよう ← 今ここ!
    String.format()、StringBuilder

次回予告

  • 第6回: CSVファイル - データの入出力
    第5回で学んだ文字列処理(split)を活用してCSVファイルを扱います

  • 第7回: 設定管理 - Propertiesクラス
    ゲームの設定ファイルを管理する方法を学びます

  • 第8回: 総合演習 - システム統合
    第1回〜第7回の知識を統合して完全なRPGシステムを構築します


学習お疲れ様でした!

文字列処理は、どんなプログラムでも必須のスキルです。
String.formatとStringBuilderを使いこなして、美しく効率的なコードを書きましょう!


本記事は教育目的で作成されています。RPGの例を通じてプログラミング概念を楽しく学習できることを目指しています。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?