ソート時に大文字と小文字のどちらを優先するかを制御する方法

Intl.CollatorのcaseFirstオプションを使用して、文字列のソート時の大文字小文字の順序を決定する

はじめに

大文字小文字のみが異なる文字列の配列をソートする場合、JavaScriptはどちらのバージョンを先にするかを決定する必要があります。appleAppleより前にすべきでしょうか、それともAppleappleより前にすべきでしょうか。アプリケーションによって、この順序に対する要件は異なります。

デフォルトでは、大文字小文字のみが異なる文字列のソート順序は、ロケールと感度設定に依存します。多くの場合、appleAppleのような文字列は同等として扱われ、その順序は予測不可能になります。アプリケーションで大文字小文字の順序が重要な場合、大文字と小文字のどちらを先にソートするかを明示的に制御する必要があります。

Intl.Collator APIは、大文字小文字の順序を決定するcaseFirstオプションを提供します。コレーターを設定して、大文字を小文字より前に配置したり、小文字を大文字より前に配置したり、ロケールのデフォルト動作を使用したりできます。このレッスンでは、caseFirstオプションの仕組み、効果が現れる場合、および実際のソートシナリオでの使用方法について説明します。

caseFirstオプションの機能

caseFirstオプションは、大文字小文字のみが異なる文字列の順序を制御します。このオプションは、"upper""lower"、または"false"の3つの文字列値を受け入れます。

"upper"に設定すると、大文字が対応する小文字より前にソートされます。文字列Appleappleより前に配置されます。

"lower"に設定すると、小文字がそれに対応する大文字よりも前にソートされます。文字列appleAppleよりも前に配置されます。

"false"(ブール値ではなく文字列値)に設定すると、照合順序はロケールのデフォルトの大文字小文字順序を使用します。これは、このオプションを指定しない場合のデフォルトの動作です。

caseFirstオプションは、大文字小文字のみが異なる文字列にのみ影響します。基本文字が異なる文字列は、この設定に関係なく、通常のアルファベット順のルールに従ってソートされます。

デフォルトの大文字小文字順序の仕組み

caseFirstオプションを指定しない場合、照合順序はロケールと感度設定に依存するデフォルトの動作を使用します。

const collator = new Intl.Collator('en-US');
const words = ['apple', 'Apple', 'APPLE'];

words.sort(collator.compare);

console.log(words);
// Output: ['apple', 'Apple', 'APPLE']

出力順序は実装とロケールに依存します。デフォルトの感度設定では、照合順序は大文字小文字の違いを考慮しますが、appleAppleAPPLEの具体的な順序は異なります。

ロケールによって、デフォルトの大文字小文字順序の規則は異なります。一部のロケールでは伝統的に小文字が先に配置され、他のロケールでは大文字が先に配置されます。デフォルトの動作に依存すると、異なる環境間で一貫性のない結果が生成されます。

caseFirst upperで大文字を先に配置する

caseFirst: "upper"を設定すると、ソート結果において大文字が常にそれに対応する小文字よりも前に配置されます。

const collator = new Intl.Collator('en-US', { caseFirst: 'upper' });
const words = ['apple', 'Apple', 'banana', 'Banana'];

words.sort(collator.compare);

console.log(words);
// Output: ['Apple', 'apple', 'Banana', 'banana']

照合順序は最初に基本文字でアルファベット順にソートし、次に各グループ内で大文字小文字順序を適用します。aで始まる単語の中では、Appleappleよりも前に配置されます。bで始まる単語の中では、Bananabananaよりも前に配置されます。

この順序は、固有名詞や大文字のタイトルを普通名詞より目立たせて表示するリストで便利です。

const collator = new Intl.Collator('en-US', { caseFirst: 'upper' });
const names = ['smith', 'Smith', 'jones', 'Jones'];

names.sort(collator.compare);

console.log(names);
// Output: ['Jones', 'jones', 'Smith', 'smith']

大文字の名前が小文字版より前に表示されるため、混在リストで固有名詞と一般的な単語を区別しやすくなります。

caseFirst lowerで小文字を先に配置する

caseFirst: "lower"を設定すると、ソート結果で小文字が常に対応する大文字より前に配置されます。

const collator = new Intl.Collator('en-US', { caseFirst: 'lower' });
const words = ['apple', 'Apple', 'banana', 'Banana'];

words.sort(collator.compare);

console.log(words);
// Output: ['apple', 'Apple', 'banana', 'Banana']

コレーターはまずアルファベット順にソートし、次に各アルファベットグループ内で小文字版を大文字版より前に配置します。

この順序は、小文字テキストがより標準的または中立的とみなされ、大文字が強調や特殊なケースのために予約されている慣例に一致します。

const collator = new Intl.Collator('en-US', { caseFirst: 'lower' });
const tags = ['javascript', 'JavaScript', 'python', 'Python'];

tags.sort(collator.compare);

console.log(tags);
// Output: ['javascript', 'JavaScript', 'python', 'Python']

小文字タグが最初に表示されます。これは小文字が正規形式を表し、大文字版があまり一般的でないバリエーションである場合に便利です。

caseFirst falseでロケールのデフォルト動作を使用する

caseFirst: "false"(文字列値)を設定すると、ロケールのデフォルトの大文字小文字順序が明示的に要求されます。これはオプションを完全に省略した場合と同じ結果になります。

const collator = new Intl.Collator('en-US', { caseFirst: 'false' });
const words = ['apple', 'Apple', 'APPLE'];

words.sort(collator.compare);

console.log(words);
// Output depends on locale implementation

出力順序は、ロケールが標準とみなすものに依存します。一部のロケールは大文字を先に定義し、他のロケールは小文字を先に定義し、大文字小文字が異なる文字列を等しいものとして扱うロケールもあります。

このオプションは、設定の選択を誤って省略したのではなく、ロケールのデフォルトを使用していることを明示したい場合に便利です。

caseFirstが効果を持たない場合

caseFirstオプションは、sensitivity設定で大文字小文字の違いが重要になる場合にのみ比較に影響します。sensitivity: "base"またはsensitivity: "accent"の場合、大文字小文字の違いは完全に無視されるため、caseFirstオプションは無関係になります。

const collator = new Intl.Collator('en-US', {
  sensitivity: 'base',
  caseFirst: 'upper'
});

const words = ['apple', 'Apple', 'APPLE'];

words.sort(collator.compare);

console.log(words);
// Output: ['apple', 'Apple', 'APPLE'] (or any order)

基本感度では、照合器は3つの文字列すべてを等しいものとして扱います。caseFirstオプションは、大文字小文字が全く考慮されないため効果がありません。ソートアルゴリズムは等しい項目の元の順序を保持する(安定ソート)ため、出力は入力順序と一致します。

caseFirstを有効にするには、sensitivity: "case"またはsensitivity: "variant"(デフォルト)を使用してください。

const collator = new Intl.Collator('en-US', {
  sensitivity: 'variant',
  caseFirst: 'upper'
});

const words = ['apple', 'Apple', 'APPLE'];

words.sort(collator.compare);

console.log(words);
// Output: ['APPLE', 'Apple', 'apple']

変異感度(大文字小文字を含むすべての違いを考慮)では、caseFirstオプションがこれらの大文字小文字が異なる文字列の順序を決定します。

一貫した大文字小文字順序による名前のソート

ユーザー名やその他の固有名詞をソートする際、一貫した大文字小文字順序により、アプリケーション全体で予測可能な結果が保証されます。

const collator = new Intl.Collator('en-US', { caseFirst: 'upper' });

const users = [
  { name: 'alice' },
  { name: 'Alice' },
  { name: 'bob' },
  { name: 'Bob' }
];

users.sort((a, b) => collator.compare(a.name, b.name));

users.forEach(user => {
  console.log(user.name);
});
// Output:
// Alice
// alice
// Bob
// bob

照合器は大文字の名前を小文字版の前に配置します。この順序により、混合データセット内で固有名詞と一般的な単語を区別しやすくなります。

制御された大文字小文字順序によるファイル名のソート

ファイルシステムには異なる大文字小文字の区別動作があります。大文字と小文字を同じものとして扱うものもあれば、異なるものとして扱うものもあります。明示的な大文字小文字順序により、基盤となるファイルシステムに関係なく、ソートされたファイルリストがユーザーの期待に一致することが保証されます。

const collator = new Intl.Collator('en-US', { caseFirst: 'lower' });

const files = ['README.md', 'readme.md', 'index.js', 'Index.js'];

files.sort(collator.compare);

console.log(files);
// Output: ['index.js', 'Index.js', 'readme.md', 'README.md']

小文字版が最初に表示され、Unixライクなシステムで小文字のファイル名がより標準的である慣例と一致します。

caseFirstと数値照合の組み合わせ

caseFirstオプションは、numericなどの他の照合オプションと併用できます。埋め込まれた数値を含む文字列を、大文字小文字順序を制御しながらソートできます。

const collator = new Intl.Collator('en-US', {
  numeric: true,
  caseFirst: 'upper'
});

const items = ['item1', 'Item1', 'item2', 'Item2', 'item10', 'Item10'];

items.sort(collator.compare);

console.log(items);
// Output: ['Item1', 'item1', 'Item2', 'item2', 'Item10', 'item10']

照合器は数値部分に数値比較を適用し、文字部分に大文字小文字順序を適用します。項目は最初に数値(1、2、10)でソートされ、次に各数値グループ内で大文字小文字によってソートされます。

caseFirstのUnicode拡張キーの使用

caseFirstオプションは、kfキーを使用してロケール識別子のUnicode拡張を通じて設定することもできます。拡張値はupperlower、およびfalseです。

const collator = new Intl.Collator('en-US-u-kf-upper');
const words = ['apple', 'Apple', 'banana', 'Banana'];

words.sort(collator.compare);

console.log(words);
// Output: ['Apple', 'apple', 'Banana', 'banana']

ロケール文字列en-US-u-kf-upperは、大文字優先の大文字小文字順序を持つ米国英語を指定します。これは、optionsオブジェクトで{ caseFirst: 'upper' }を渡すのと同じ結果を生成します。

Unicode拡張とoptionsオブジェクトの両方がcaseFirstを指定する場合、optionsオブジェクトが優先されます。

const collator = new Intl.Collator('en-US-u-kf-upper', {
  caseFirst: 'lower'
});

const words = ['apple', 'Apple'];

words.sort(collator.compare);

console.log(words);
// Output: ['apple', 'Apple']

optionsオブジェクトはcaseFirst: 'lower'を指定し、ロケール文字列のkf-upper拡張を上書きします。collatorは小文字優先の順序を使用します。

collatorが使用しているcaseFirst値の確認

resolvedOptions()メソッドは、caseFirst設定を含む、collatorが使用している実際のオプションを返します。

const collator = new Intl.Collator('en-US', { caseFirst: 'upper' });
const options = collator.resolvedOptions();

console.log(options.caseFirst);
// Output: "upper"

これは、特にUnicode拡張とoptionsオブジェクトを組み合わせる場合に、collatorが期待される構成を持っていることをデバッグまたは検証するのに役立ちます。

const collator = new Intl.Collator('en-US-u-kf-lower');
const options = collator.resolvedOptions();

console.log(options.caseFirst);
// Output: "lower"

解決されたオプションは、optionsオブジェクトが上書きしない場合、Unicode拡張設定を反映します。

各caseFirst値を使用するタイミング

caseFirst: "upper"を使用する場合:

  • 固有名詞やタイトルを一般的な単語の前に表示したい場合
  • アプリケーションの規約で大文字のテキストをより重要なものとして扱う場合
  • 大文字版が正規である名前をソートする場合

caseFirst: "lower"を使用する場合:

  • 小文字のテキストを標準形式として最初に表示したい場合
  • アプリケーションの規約で小文字をデフォルトとし、大文字を特別なものとして扱う場合
  • 小文字がより一般的な技術的識別子をソートする場合

次の場合に caseFirst: "false" を使用します:

  • ロケール固有の規則に従いたい場合
  • 大文字小文字が異なる文字列の順序がアプリケーションにとって重要でない場合
  • オプションを誤って省略したのではなく、デフォルトを使用していることを明示したい場合