정렬 시 대문자와 소문자 중 어느 것이 먼저 오는지 제어하는 방법

Intl.Collator의 caseFirst 옵션을 사용하여 문자열 정렬 시 대소문자 순서를 결정하세요

소개

대소문자만 다른 문자열 배열을 정렬할 때 JavaScript는 어떤 버전이 먼저 나와야 하는지 결정해야 합니다. appleApple보다 먼저 나와야 할까요, 아니면 Appleapple보다 먼저 나와야 할까요? 애플리케이션마다 이 순서에 대한 요구 사항이 다릅니다.

기본적으로 대소문자만 다른 문자열의 정렬 순서는 로케일 및 민감도 설정에 따라 달라집니다. 많은 경우 appleApple와 같은 문자열은 동일하게 처리되어 순서를 예측할 수 없습니다. 애플리케이션에서 대소문자 순서가 중요한 경우 대문자 또는 소문자가 먼저 정렬되는지에 대한 명시적인 제어가 필요합니다.

Intl.Collator API는 대소문자 순서를 결정하는 caseFirst 옵션을 제공합니다. collator를 구성하여 대문자를 소문자보다 먼저 배치하거나, 소문자를 대문자보다 먼저 배치하거나, 로케일의 기본 동작을 사용할 수 있습니다. 이 레슨에서는 caseFirst 옵션이 작동하는 방식, 효과가 있는 경우, 실제 정렬 시나리오에서 사용하는 방법을 설명합니다.

caseFirst 옵션의 기능

caseFirst 옵션은 대소문자만 다른 문자열의 순서를 제어합니다. 세 가지 문자열 값을 허용합니다: "upper", "lower" 또는 "false".

"upper"로 설정하면 대문자가 해당 소문자보다 먼저 정렬됩니다. 문자열 Appleapple보다 먼저 나타납니다.

"lower"로 설정하면 소문자가 해당 대문자보다 먼저 정렬됩니다. 문자열 appleApple보다 먼저 나타납니다.

"false"(불리언이 아닌 문자열 값)로 설정하면 collator는 로케일의 기본 대소문자 순서를 사용합니다. 이는 옵션을 지정하지 않을 때의 기본 동작입니다.

caseFirst 옵션은 대소문자를 제외하고 동일한 문자열에만 영향을 줍니다. 기본 문자가 다른 문자열은 이 설정과 관계없이 일반적인 알파벳 규칙에 따라 정렬됩니다.

기본 대소문자 정렬 작동 방식

caseFirst 옵션을 지정하지 않으면 collator는 로케일 및 민감도 설정에 따라 달라지는 기본 동작을 사용합니다.

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

words.sort(collator.compare);

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

출력 순서는 구현 및 로케일에 따라 다릅니다. 기본 민감도 설정에서 collator는 대소문자 차이를 고려하지만 apple, Apple, APPLE의 구체적인 순서는 다양합니다.

로케일마다 기본 대소문자 정렬 규칙이 다릅니다. 일부 로케일은 전통적으로 소문자를 먼저 배치하고 다른 로케일은 대문자를 먼저 배치합니다. 기본 동작에 의존하면 다양한 환경에서 일관되지 않은 결과가 생성됩니다.

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']

collator는 먼저 기본 문자를 기준으로 알파벳순으로 정렬한 다음 각 그룹 내에서 대소문자 순서를 적용합니다. 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']

collator는 먼저 알파벳순으로 정렬한 다음 각 알파벳 그룹 내에서 소문자 버전을 대문자 버전보다 먼저 배치합니다.

이 정렬은 소문자 텍스트가 더 표준적이거나 중립적인 것으로 간주되고 대문자는 강조나 특수한 경우를 위해 예약되는 규칙과 일치합니다.

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: "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)

기본 민감도에서 collator는 세 문자열을 모두 동일하게 취급합니다. 대소문자가 전혀 고려되지 않기 때문에 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']

variant 민감도(대소문자를 포함한 모든 차이를 고려)를 사용하면 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와 같은 다른 collation 옵션과 함께 작동합니다. 대소문자 순서를 제어하면서 숫자가 포함된 문자열을 정렬할 수 있습니다.

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']

collator는 숫자 부분에 대해 숫자 비교를 적용하고 문자 부분에 대해 대소문자 순서를 적용합니다. 항목은 먼저 숫자 값으로 정렬되고(1, 2, 10), 각 숫자 그룹 내에서 대소문자로 정렬됩니다.

caseFirst에 대한 Unicode 확장 키 사용하기

caseFirst 옵션은 kf 키를 사용하여 로케일 식별자의 Unicode 확장을 통해서도 설정할 수 있습니다. 확장 값은 upper, lower, 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는 대문자 우선 대소문자 순서를 사용하는 미국 영어를 지정합니다. 이는 옵션 객체에 { caseFirst: 'upper' }를 전달하는 것과 동일한 결과를 생성합니다.

Unicode 확장과 옵션 객체가 모두 caseFirst를 지정하면 옵션 객체가 우선합니다.

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']

옵션 객체는 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"

이는 디버깅이나 collator가 예상된 구성을 가지고 있는지 확인하는 데 유용하며, 특히 Unicode 확장을 옵션 객체와 결합할 때 유용합니다.

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

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

해결된 옵션은 옵션 객체가 이를 재정의하지 않을 때 유니코드 확장 설정을 반영합니다.

각 caseFirst 값을 사용해야 하는 경우

caseFirst: "upper"를 사용하는 경우:

  • 고유 명사나 제목이 일반 단어보다 먼저 나타나기를 원할 때
  • 애플리케이션 규칙에서 대문자 텍스트를 더 중요하게 취급할 때
  • 대문자 버전이 정식인 이름을 정렬할 때

caseFirst: "lower"를 사용하는 경우:

  • 소문자 텍스트가 표준 형식으로 먼저 나타나기를 원할 때
  • 애플리케이션 규칙에서 소문자를 기본으로, 대문자를 특수한 것으로 취급할 때
  • 소문자가 더 일반적인 기술 식별자를 정렬할 때

caseFirst: "false"를 사용하는 경우:

  • 로케일별 규칙을 따르고자 할 때
  • 대소문자가 다른 문자열의 순서가 애플리케이션에 중요하지 않을 때
  • 실수로 옵션을 생략한 것이 아니라 기본값을 사용하고 있음을 명시적으로 표현하고자 할 때