大文字・小文字変換

テキストを camelCase、snake_case、kebab-case、Title Case などに変換。ロケール対応の大文字小文字変換と行操作をブラウザ内で。

テキスト

表記形式

  • UPPERCASE
    XMLHTTPREQUEST HANDLER FOR ISTANBUL CITY GUIDE
  • lowercase
    xmlhttprequest handler for istanbul city guide
  • Title Case
    Xmlhttprequest Handler For Istanbul City Guide
  • Sentence case
    Xmlhttprequest handler for istanbul city guide
  • camelCase
    xmlHttpRequestHandlerForIstanbulCityGuide
  • PascalCase
    XmlHttpRequestHandlerForIstanbulCityGuide
  • snake_case
    xml_http_request_handler_for_istanbul_city_guide
  • kebab-case
    xml-http-request-handler-for-istanbul-city-guide
  • CONSTANT_CASE
    XML_HTTP_REQUEST_HANDLER_FOR_ISTANBUL_CITY_GUIDE
  • dot.case
    xml.http.request.handler.for.istanbul.city.guide

行操作

結果
XMLHttpRequest handler for istanbul city guide

行数: 1

一つの単語分割から生まれる十の表記形式

文字の大小を変えることは、プログラムができるもっとも単純な作業に見えますが、驚くほど多くの実際のバグを生んできました。理由の一つは、「大文字小文字」が実際には一つの名前を共有する二つの別々の問題だからです。テキストを UPPERCASE や lowercase にするのは Unicode が定める一文字ずつの対応付けです。camelCase や snake_case にするのはまったく別で、まず単語がどこにあるかを決め、そのうえで大小を変えて結合し直す必要があります。このツールは両方を行い、すべての結果を一度に示し、そして何より、どの答えが言語設定に左右されるのかを教えます。

プログラマー向けの六つの形式はすべて同じ単語分割から導かれるため、互いに食い違うことがありません。その境界は次のとおりです。

  • 小文字の次に大文字が来ると新しい単語が始まります。これにより fooBar は foo と Bar になります。
  • 大文字の連続は次の単語が始まるところ、つまり小文字の直前にある最後の大文字で終わります。XMLHttpRequest は XML、Http、Request になり、IOError は IO と Error になります。
  • 数字の次に大文字が来ると新しい単語が始まるため、html5Parser は html5 と Parser になります。
  • 文字でも数字でも結合記号でもないものはすべて単語を区切ります。空白、アンダースコア、ハイフン、ドット、句読点などです。

それ以外の場合、数字は直前の単語にくっついたままです。だから utf8 や address2 はそのまま通ります。これは lodash との意図的な相違です。lodash の分割器は数字の連続をすべて独立した単語として扱い、utf8 を utf_8 にします。技術的には一貫していますが、変数に名前を付けた人が意図したものではありません。

この分割は ASCII の文字クラスではなく Unicode のプロパティで書かれているため、英語に限定されません。キリル文字の識別子もラテン文字と同じように大小の境界で分かれます。そもそも大文字小文字の区別がない文字体系 — ヘブライ文字、アラビア文字、中国語、日本語、韓国語 — には見つけるべき境界がないので、区切り文字だけで分割されます。これは制限ではなく正しい答えです。

頭字語には正しい答えが二つある

XMLHttpRequest が XML、Http、Request に分割されたあと、それを PascalCase として組み直す段階で、唯一の正解がない問いが生じます。すべての単語を組み直すと XmlHttpRequest になります。これは lodash が生成するものであり、Google の Java スタイルガイドが求めるものでもあります。頭字語を普通の単語として扱えば、ParseXmlDocument のような名前でも境界が見えたままになるからです。大文字の連続を保つと XMLHttpRequest になります。これはブラウザ API の実際の名前であり、DOM の大半と ‎.NET の多くが従う慣習です。

どちらも実際のコードベースで使われているため、このツールは両方を提供し、既定では組み直します。このオプションが影響するのは camelCase と PascalCase だけです。ほかの形式はどのみち単語全体を組み直すので、XMLHttpRequest はどちらでも xml_http_request と XML_HTTP_REQUEST になります。

一点だけは選択できず固定されています。camelCase の名前の最初の単語は、頭字語であっても必ずすべて小文字になります。保持すれば PascalCase になってしまい、中途半端に保持すれば xMLHttpRequest という、どのスタイルガイドも推奨せず、どの読み手もつまずく形になるからです。したがって XMLHttpRequest はどちらの設定でも xmlHttpRequest になり、一方 parseXMLDocument は指定すれば途中の頭字語をそのまま保ちます。

トルコ語の i と、ロケールが選択である理由

JavaScript には大文字化のメソッドが二つあり、その違いは本番システムを壊してきました。toUpperCase はロケールに依存しない Unicode の対応付けを適用し、文字 i は I になります。toLocaleUpperCase はその言語固有の規則を適用し、トルコ語とアゼルバイジャン語では i の大文字は点付きの İ になります。これらのアルファベットには点のない ı もあり、その大文字が I だからです。トルコ語利用者の入力を本人のロケールで大文字化してプロトコルのキーワードと比較すると、ほとんど見分けのつかない文字のせいで比較が失敗します。

これは文字列処理における最も一般的な国際化バグであり、自分の身に起きるまで目に見えません。そのため、このツールは決して推測しません。既定はロケールに依存しない対応付けで、これは識別子、プロトコルのトークン、HTTP ヘッダー、データベースのキーが必要とするものです。言語を選ぶとその言語の規則に切り替わり、そして選択が結果を変えるたびに、ロケールに依存しない答えを並べて表示します。その言語が何をしたのかがそのまま見えるようにするためです。

'i'.toUpperCase()             // 'I'
'i'.toLocaleUpperCase('tr')   // 'İ'  dotted capital
'I'.toLocaleLowerCase('tr')   // 'ı'  dotless lowercase
'ISTANBUL'.toLocaleLowerCase('tr')  // 'ıstanbul'

ほかにも三つの言語が答えを変えるため、そのすべてを用意しています。リトアニア語は、別のアクセントを伴う大文字を小文字にするとき i の上の点を残すので、Ì は結合ドットと結合グレイヴを伴う i になり、合成済みの単一文字 ì にはなりません。ギリシャ語は大文字化のときにトノスを落とすので、άνθρωπος は ΆΝΘΡΩΠΟΣ ではなく ΑΝΘΡΩΠΟΣ になります。ギリシャ語では大文字にアクセントを書かないからです。アゼルバイジャン語はトルコ語と点のある i と点のない i を共有します。

有名な二つの事例はロケール規則ではありません。どちらがどちらかを知っておく価値があります。ドイツ語の ß はあらゆるロケールで SS になります。これはドイツ語の規則ではなく Unicode の SpecialCasing 規則だからです。だからこそ対応付けは可逆ではなく、SS は ss に戻ります。またギリシャ語のシグマは語末で σ ではなく終形の ς になりますが、これはどこでも同じです。文字の位置に対する文脈条件であって言語設定ではありません。どちらもロケールを選ばないままこのツールで確認できます。

Title case と Sentence case はここでは機械的

このツールの Title Case は各単語の最初の文字を大文字にし、残りを小文字にします。Sentence case はテキストの最初の文字と、それ以降の各文の最初の文字を大文字にします。文はピリオド、感嘆符、疑問符、または三点リーダーのあとに空白が続くところで終わります。どちらもまず入力を小文字にします。だからこそ、大声で届いたテキストにも役立ちます。

これらは意図的に機械的な規則であり、代案を説明しておく価値があります。英語のスタイルガイドはタイトルケースを、どの短い語を小文字のままにするかで定義します。そしてその一覧についても、コロンのあとの語を大文字にするかについても、四文字以上の前置詞についても互いに食い違っています。そのどれかをここで適用することは、ヘブライ語や日本語やトルコ語で書く読者に、その概念がそもそも移らないまま米国の新聞の慣習を届けることを意味します。すべての語を大文字にする方が予測でき、どの言語でも説明でき、あとから手で直すのも簡単です。

Sentence case の空白条件は、3.5 metres が 3.5 Metres にならないようにするものです。そこでのピリオドのあとには数字が続くからです。ただし略語は解決しません。e.g. this は依然として偽の文を始めてしまいます。「e.g.」が文末ではないと知るには、その言語の略語の一覧が必要だからです。単語の中のアポストロフィも新しい単語を始めません。したがって it's は一度だけ大文字になり、It'S ではなく It's になります。

並べ替え: アルファベット順かバイト順か

行操作は空白の除去、重複の削除、並べ替え、逆順、行番号付けを行いますが、並べ替えはロケールの問題を二度目に持ち出します。アルファベット順は Unicode の性質ではなく言語の性質です。ドイツ語は ä を a の隣に置くので a、ä、z の順になります。スウェーデン語はそれを別の文字としてアルファベットの末尾に置くので a、z、ä の順になります。どちらもその国では正しく、ツールはページ上部で選んだロケールを使います。

もう一つの選択肢はコードポイント順で、答えが別の何かと一致しなければならないときに必要になります。コードポイントによる比較は UTF-8 のバイト順であり、LC_ALL=C sort や git、そして多くのプログラミング言語の既定の文字列比較が生成するものをそのまま再現します。つまりすべての大文字がすべての小文字より前に来るので、B は a より前です。ツールの出力と突き合わせるときはこちらを、人が読む一覧を作るときは照合順序を選んでください。

数値の自然順 — item2 が item10 より後ではなく前に来ること — は照合順序の機能なので、アルファベット順の規則でのみ利用できます。バイト順には文字列の中の数値という概念がなく、それが模倣している並べ替えにもありません。両方を同時に提供することは、出力が果たせない約束をすることになります。

操作は決まった順序で実行され、その順序には意味があります。空白の除去は重複の削除より前に行われるので、末尾の空白だけが違っていた二行は同じ行として認識されます。並べ替えは逆順より前に行われるので、逆順は常に「いま見えているものを逆にする」ことを意味します。空行の数と削除された重複の数はどちらも報告されます。黙って数えることこそ、一覧が思っていたものと違っていたことに気づけなくなる原因だからです。

どこで動くか

すべてはブラウザの中で行われます。大文字小文字の対応付けは JavaScript エンジン自身の Unicode 実装から、照合順序は Intl.Collator から得られます。したがって答えは、何年も前に誰かが写した表ではなく、実際にあなたの文字列を処理することになる実行環境と一致します。貼り付けた内容がアップロードされたり保存されたり記録されたりすることはないので、名前やログ行、そして大文字小文字を変えるためだけにサーバーへ送りたくないものにも安心して使えます。

よくある質問

入力したテキストはサーバーに送信されますか?
いいえ。すべての変換は JavaScript エンジン自身の Unicode 大文字小文字対応付けを使ってブラウザ内で実行され、貼り付けた内容がアップロードされたり記録されたりすることはありません。
トルコ語を選ぶと結果が 2 つ表示されるのはなぜですか?
トルコ語が結果を変えるからです。トルコ語のアルファベットには点のある i と点のない ı の両方があるため、i の大文字は I ではなく İ になります。ロケールが結果を変えるたびに、ツールはロケールに依存しない答えを並べて表示します。識別子やプロトコルのトークンにはそちらが必要だからです。
ロケールに依存しない対応付けと言語の対応付けのどちらを使うべきですか?
機械が読むもの — 識別子、HTTP ヘッダー、データベースのキー、プロトコルのトークン、ファイル名 — にはロケールに依存しない対応付けを使ってください。人がその言語で読むテキストには言語の対応付けを使ってください。この二つを取り違えることが、古典的なトルコ語 i のバグです。
XMLHttpRequest が XmlHttpRequest に変換されるのはなぜですか?
既定では頭字語を組み直すからで、これは lodash やいくつかの主要なスタイルガイドが行っていることです。頭字語のオプションを有効にすると大文字の連続が保たれ、XMLHttpRequest が戻ってきます。このオプションは camelCase と PascalCase にのみ影響します。ほかの形式はどのみち各単語を組み直すからです。
lodash が分割する utf8 が、ここでは一語のままなのはなぜですか?
ここでは数字が直前の単語にくっつくため、utf8 と address2 はそのまま通ります。数字の次に大文字が来る場合は新しい単語が始まり、それが html5Parser を html5 と Parser に分けています。
Title Case が of や the のような短い語まで大文字にするのはなぜですか?
規則が意図的に機械的だからです。英語のスタイルガイドはどの短い語を小文字のままにするかで互いに食い違っており、その慣習はこのサイトが扱うほかの言語には移りません。すべての語を大文字にする方が予測でき、手で直すのも簡単です。
コードポイント順のときに数値の自然順を使えないのはなぜですか?
自然順は照合順序の機能です。コードポイント順はバイト順であり、文字列の中の数値という概念がありません。それが再現している LC_ALL=C sort にもありません。両方を同時に提供すると、模倣しているツールともはや一致しない出力になってしまいます。
ロケールを選ばなくても ß が SS になるのはなぜですか?
その対応付けがドイツ語の規則ではなく Unicode の SpecialCasing 規則だからで、どこでも適用されます。また可逆でもありません。SS は ß ではなく ss になります。ギリシャ語の終形シグマも同じ仕組みで、ロケールではなく文字の位置によって決まります。