`titleize`がUnicode小文字を正しく大文字化するよう修正

rails/rails

Inflector#titleizeのASCII限定の正規表現を修正し、đéüñćなどのUnicode小文字も正しくタイトルケースに変換できるようになりました。

背景

Inflector#titleize は、単語の先頭文字を大文字化するために正規表現 [a-z] を使用していましたが、これはASCII範囲の小文字のみを対象としていました。そのため、ćđéüñといったラテン拡張文字を含む単語の先頭文字は、大文字化の対象として認識されずにそのまま小文字で出力されるという問題がありました。

PR本文の例が示すように、titleize("ćasim đipa")"Ćasim Đipa" を返すべきところ、"ćasim đipa" のまま変化しないという動作になっていました。多言語対応が求められるアプリケーションでは、この挙動はサイレントな不具合として現れます。

技術的な変更

activesupport/lib/active_support/inflector/methods.rbgsub 正規表現パターンを1文字変更することで修正が行われました。

変更前:

humanize(underscore(word), keep_id_suffix: keep_id_suffix).gsub(/\b(?<!\w[''\'`()])[a-z]/) do |match|
  match.capitalize
end

変更後:

humanize(underscore(word), keep_id_suffix: keep_id_suffix).gsub(/\b(?<!\w[''\'`()])\p{Lower}/) do |match|
  match.capitalize
end

Rubyの正規表現エンジンが対応するUnicode文字クラス \p{Lower}(別名 \p{Ll})は、ASCII小文字を含むすべてのUnicode小文字カテゴリの文字にマッチします。[a-z] の26文字からUnicode全域の小文字へと対象が広がります。既存の否定後読み (?<!\w[''\'()])\bによる単語境界の判定ロジックはそのまま維持されており、アポストロフィ付き単語(Fred's` など)の処理も引き続き正しく動作します。

テストケースには "über ñoño" => "Über Ñoño" が追加され、üñÜÑ といったラテン拡張文字でのタイトルケース変換が期待どおりに動作することが検証されています。

設計判断

最小差分での修正方針 が採られており、変更はパターン文字列の [a-z]\p{Lower} に置き換える1行のみです。

この変更はあくまで正規表現パターンの修正であり、humanizeunderscore などの前処理ステップ、あるいは capitalize を呼び出すブロック自体は変更されていません。修正以前は「正規表現がマッチしないためにブロック自体が実行されない」ことが問題の本質であり、大文字化ロジックそのものには問題はありませんでした。

まとめ

1文字のパターン変更により、titleize のUnicode対応が完成しました。[a-z] という暗黙のASCII前提が \p{Lower} に置き換わることで、ラテン拡張文字を含む多言語テキストに対しても正しいタイトルケース変換が保証されます。

記事メタデータ

Generated by:
Claude Sonnet 4.6 for DiffDaily
LLM Trace:
cbd26f72

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
リトライ後承認
Review Count:
2回 (改善を経て承認)
Reviewed by:
Gemini 2.5 Pro for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

リード文、背景、技術的な変更、まとめの「総論→各論→結論」構成が明確で、ガイドラインに完全に準拠しています。任意項目の「設計判断」も含まれており、記事の深みを増しています。

カスタムMarkdown構文 ✓ PASS

シンタックスハイライト・GitHubリンク記法の正確性

ファイル名付きシンタックスハイライト(```ruby:ファイルパス)とGitHubのPRリンク記法([#57071](URL))が正しく使用されています。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

正規表現のUnicode文字クラス(\p{Lower})やActive SupportのInflectorに関する解説は、専門知識を持つエンジニアを対象としており、過度な初心者向けの説明がなく適切です。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションが総論→各論で構成され、各段落はトピックセンテンスで始まり、1段落1トピックが守られています。段落の長さも適切で、非常に読みやすい構成です。

Diff内容との照合 ⚠ WARNING

コードブロックとDiff内容の一致

コード引用はDiffの内容をほぼ正確に反映していますが、正規表現内のアポストロフィが異なります。Diffでは`’`(U+2019)が使われていますが、記事では`'`(U+0027)になっています。これは軽微な差異であり、技術的な理解を妨げるものではありません。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

「Inflector」「正規表現」「Unicode文字クラス」「否定後読み」などの技術用語が文脈に応じて正確に使用されています。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

`[a-z]`がASCIIのみにマッチする問題点と、`\p{Lower}`がUnicode全域の小文字に対応する解決策であるという説明は、技術的に正確かつ論理的です。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

記事内のすべての主張(問題の背景、コード変更、テストケースの追加など)は、提供されたPRのDescriptionとDiffによって裏付けられており、ハルシネーションは検出されませんでした。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR番号(#57071)が正確に記載・リンクされています。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事のタイトルは「`titleize`がUnicode小文字を正しく大文字化するよう修正」であり、PRの主題を正確に反映しています。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

記事に含まれる知識はすべてPR情報から導出可能であり、サポート期間やリリース日程といったPR外の根拠のない情報は含まれていません。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

「〜でした」「〜になりました」といった時間表現は、変更前後の状態を正確に記述しており、PR情報との矛盾はありません。