Java Tips | 文字列処理:英字抽出

Java Java
スポンサーリンク

英字抽出は「ごちゃ混ぜ文字列から“アルファベットだけ”をすくい上げる」技

業務システムでは、「商品名に英字と数字と日本語が混ざっている」「ログにIDやコードが埋まっている」「外部システムから来た文字列がカオス」という状況がよくあります。
そこから「英字だけ欲しい」「英字の塊(コード)だけ欲しい」「文章中のすべての英単語っぽいものを拾いたい」といったニーズが出てきます。

このときに役立つのが「英字抽出」のユーティリティです。
ポイントは、「1文字ずつの英字が欲しいのか」「連続した英字の塊(単語・コード)が欲しいのか」を最初に決めておくことです。


基本の考え方:「連続した英字の塊」を1つの単語・コードとして扱う

正規表現で「英字のかたまり」を見つける

まずは一番よくある、「連続した英字を1つの塊として扱う」パターンからいきます。
例えば、次のような文字列があるとします。

商品コード: ABC123-JP 説明: Premium Coffee 200g

ここから「ABC」「JP」「Premium」「Coffee」を取り出したい、というイメージです。

Java では、正規表現 [A-Za-z]+ を使うと「1文字以上の連続した英字」にマッチできます。
これを Matcher#find() で繰り返し拾っていくのが基本パターンです。


連続した英字をすべて抽出するユーティリティ

文字列中の「英字の塊」を List<String> で返す

まずは、「文字列中に出てくる英字の塊を全部文字列として集める」ユーティリティを作ります。

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public final class AlphaExtractor {

    private static final Pattern ALPHAS = Pattern.compile("[A-Za-z]+");

    private AlphaExtractor() {}

    public static List<String> extractAllAlphaBlocks(String text) {
        List<String> result = new ArrayList<>();
        if (text == null || text.isEmpty()) {
            return result;
        }
        Matcher m = ALPHAS.matcher(text);
        while (m.find()) {
            result.add(m.group());
        }
        return result;
    }
}
Java

使い方はこうなります。

String s = "商品コード: ABC123-JP 説明: Premium Coffee 200g";
List<String> alphas = AlphaExtractor.extractAllAlphaBlocks(s);

System.out.println(alphas); // [ABC, JP, Premium, Coffee]
Java

ここで深掘りしたい重要ポイントは、「matches() ではなく find() をループしている」ことです。
matches() は「文字列全体がパターンに一致するか」を見るのに対し、find() は「文字列の中から、パターンに一致する部分を順番に見つけていく」ためのメソッドです。
英字抽出のように「文章の中から何度も出てくる英字の塊を全部拾いたい」場合は、find() のループが基本形になります。


例題:文章中の「最初の英字の塊だけ」を取りたい

「一番最初に出てくる英字コード」を 1つだけ返す

よくあるのが、「メッセージ中の最初の英字コードだけ欲しい」というパターンです。
例えば、「エラーメッセージからエラーコード(英字)だけ取りたい」といったケースです。

import java.util.regex.Matcher;

public final class AlphaExtractor {

    private static final Pattern ALPHAS = Pattern.compile("[A-Za-z]+");

    private AlphaExtractor() {}

    public static String extractFirstAlphaBlock(String text) {
        if (text == null || text.isEmpty()) {
            return null;
        }
        Matcher m = ALPHAS.matcher(text);
        if (m.find()) {
            return m.group();
        }
        return null;
    }
}
Java

使い方はこうです。

String msg = "ERROR_CODE[NET-105] 接続に失敗しました。";
String codePrefix = AlphaExtractor.extractFirstAlphaBlock(msg);

System.out.println(codePrefix); // ERROR
Java

ここで深掘りしたいのは、「“最初の1つだけ”という要件をメソッド名と戻り値の型で表現している」ことです。
extractAll... は List、extractFirst... は単一値(または null)という形にしておくと、呼び出し側が「このメソッドは何個返してくるのか」を直感的に理解できます。


英字だけを連結して「英字だけの文字列」を作る

「英字以外を全部捨てて、英字だけをつなげたい」

ときどき、「文字列から英字だけを抜き出して、1つの文字列にしたい」というニーズもあります。
例えば、「ABC-123-xyz から ABCxyz だけ欲しい」といったケースです。

これは「英字以外を全部削除する」という発想でも書けますが、
ここでは「英字の塊を全部拾ってから連結する」パターンで書いてみます。

public final class AlphaExtractor {

    private static final Pattern ALPHAS = Pattern.compile("[A-Za-z]+");

    private AlphaExtractor() {}

    public static String extractAllAlphasAsSingleString(String text) {
        if (text == null || text.isEmpty()) {
            return "";
        }
        StringBuilder sb = new StringBuilder();
        Matcher m = ALPHAS.matcher(text);
        while (m.find()) {
            sb.append(m.group());
        }
        return sb.toString();
    }
}
Java

使い方はこうです。

String s = "ABC-123-xyz_456";
String onlyAlpha = AlphaExtractor.extractAllAlphasAsSingleString(s);

System.out.println(onlyAlpha); // ABCxyz
Java

ここでの重要ポイントは、「“英字だけを残す”という要件を、正規表現+ビルダーで明示的に表現している」ことです。
text.replaceAll("[^A-Za-z]", "") のように「非英字を全部消す」書き方もありますが、
extractAllAlphaBlocks と同じパターンで書いておくと、「どこで何をしているか」が揃って読みやすくなります。


大文字・小文字の扱いをどうするか

「大文字・小文字を区別するか」「揃えるか」を最初に決める

英字抽出では、「大文字と小文字を区別するか」「結果をすべて大文字(または小文字)に揃えるか」という設計も重要です。

例えば、「コードは大文字で扱いたい」という要件なら、抽出後に toUpperCase() をかけるユーティリティを用意しておくと便利です。

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public final class AlphaExtractor {

    private static final Pattern ALPHAS = Pattern.compile("[A-Za-z]+");

    private AlphaExtractor() {}

    public static List<String> extractAllAlphaBlocksUpper(String text) {
        List<String> result = new ArrayList<>();
        if (text == null || text.isEmpty()) {
            return result;
        }
        Matcher m = ALPHAS.matcher(text);
        while (m.find()) {
            result.add(m.group().toUpperCase(Locale.ROOT));
        }
        return result;
    }
}
Java

使い方はこうです。

String s = "code: abc123, Region: jp, Owner: Smith";
System.out.println(AlphaExtractor.extractAllAlphaBlocksUpper(s));
// [CODE, ABC, REGION, JP, OWNER, SMITH]
Java

ここで深掘りしたいのは、「大文字・小文字の扱いを“呼び出し側の気分”に任せず、ユーティリティのメソッド名と実装で明示する」ことです。
extractAllAlphaBlocks はそのまま、extractAllAlphaBlocksUpper は大文字に揃える、といった形で分けておくと、
後から読んだときに「このコードは何を期待しているのか」が一目で分かります。


例題:英字コードだけを抜き出して一覧にする

「ログ中の英字コードを全部拾って分析したい」

例えば、次のようなログが大量にあるとします。

2025-01-30 INFO CODE=NET_ERR_01 message=Connection failed
2025-01-30 INFO CODE=AUTH_WARN_02 message=Password weak

ここから NET_ERR_01AUTH_WARN_02 のような「英字+アンダースコア+数字」のコードだけを抜き出したい、というケースです。

この場合は、「英字だけ」ではなく「英字を含む特定フォーマットのコード」を対象にしたほうが実務的です。

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public final class CodeExtractor {

    // 例: NET_ERR_01, AUTH_WARN_02 など
    private static final Pattern CODE_PATTERN =
            Pattern.compile("[A-Z]+(?:_[A-Z]+)*_\\d+");

    private CodeExtractor() {}

    public static List<String> extractAllCodes(String text) {
        List<String> result = new ArrayList<>();
        if (text == null || text.isEmpty()) {
            return result;
        }
        Matcher m = CODE_PATTERN.matcher(text);
        while (m.find()) {
            result.add(m.group());
        }
        return result;
    }
}
Java

使い方はこうです。

String logs = """
2025-01-30 INFO CODE=NET_ERR_01 message=Connection failed
2025-01-30 INFO CODE=AUTH_WARN_02 message=Password weak
""";

System.out.println(CodeExtractor.extractAllCodes(logs));
// [NET_ERR_01, AUTH_WARN_02]
Java

ここでの重要ポイントは、「“英字抽出”を土台にしつつ、業務で意味のあるフォーマット(コード)に特化したパターンをユーティリティとして切り出している」ことです。
単に [A-Za-z]+ で全部拾うのではなく、「このプロジェクトで“コード”と呼ぶものはこういう形」というルールを正規表現で固定しておくと、
ログ解析や集計が格段にやりやすくなります。


まとめ:英字抽出ユーティリティで身につけたい感覚

英字抽出は、「文字と数字、日本語や記号が混ざった世界から、“アルファベットとして意味のある部分”だけをすくい上げる」技です。

押さえておきたい感覚は、まず「連続した英字の塊を [A-Za-z]+ で拾い、Matcher#find() のループで全部集める」という基本パターン。
次に、「extractAll...extractFirst......Blocks...AsSingleString のように、メソッド名と戻り値の型で“何をどの単位で取りたいのか”をはっきり表現する」こと。
そして、「大文字・小文字の扱いや、“英字を含むコード形式”などの業務ルールをユーティリティに閉じ込め、プロジェクト全体で同じ抽出ロジックを共有する」ことです。

もしあなたのコードのどこかに、text.replaceAll("[^A-Za-z]", "")text.matches(".*[A-Za-z].*") のような断片的な処理が散らばっているなら、
それを題材にして、ここで作った AlphaExtractorCodeExtractor のようなユーティリティにまとめてみてください。
それだけで、「読みやすくて、再利用できて、仕様変更にも強い英字抽出」に、一段レベルアップできます。

タイトルとURLをコピーしました