Cómo controlar si las mayúsculas o minúsculas van primero en la ordenación

Usa la opción caseFirst en Intl.Collator para determinar el orden de mayúsculas y minúsculas al ordenar cadenas

Introducción

Cuando ordenas un array de cadenas que difieren solo en su capitalización, JavaScript necesita decidir qué versión va primero. ¿Debería apple ir antes que Apple, o debería Apple ir antes que apple? Diferentes aplicaciones tienen diferentes requisitos para este ordenamiento.

Por defecto, el orden de clasificación para cadenas que difieren solo en mayúsculas y minúsculas depende de la configuración regional y de sensibilidad. En muchos casos, cadenas como apple y Apple se tratan como iguales, haciendo que su orden sea impredecible. Cuando el orden de mayúsculas y minúsculas importa para tu aplicación, necesitas un control explícito sobre si las letras mayúsculas o minúsculas se ordenan primero.

La API Intl.Collator proporciona una opción caseFirst que determina el orden de mayúsculas y minúsculas. Puedes configurar el comparador para colocar las letras mayúsculas antes que las minúsculas, las letras minúsculas antes que las mayúsculas, o usar el comportamiento predeterminado del locale. Esta lección explica cómo funciona la opción caseFirst, cuándo tiene efecto y cómo usarla en escenarios de ordenación prácticos.

Qué hace la opción caseFirst

La opción caseFirst controla el orden de las cadenas que difieren solo en su capitalización. Acepta tres valores de cadena: "upper", "lower" o "false".

Cuando se establece en "upper", las letras mayúsculas se ordenan antes que sus equivalentes en minúsculas. La cadena Apple va antes que apple.

Cuando se establece en "lower", las letras minúsculas se ordenan antes que sus equivalentes en mayúsculas. La cadena apple va antes que Apple.

Cuando se establece en "false" (el valor de cadena, no el booleano), el comparador utiliza el orden de mayúsculas y minúsculas predeterminado del locale. Este es el comportamiento predeterminado cuando no especificas la opción.

La opción caseFirst solo afecta a las cadenas que son idénticas excepto por el uso de mayúsculas y minúsculas. Las cadenas que difieren en sus letras base se ordenan según las reglas alfabéticas normales independientemente de esta configuración.

Cómo funciona el orden de mayúsculas y minúsculas predeterminado

Sin especificar la opción caseFirst, el comparador utiliza el comportamiento predeterminado que depende de la configuración regional y de sensibilidad.

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

words.sort(collator.compare);

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

El orden de salida depende de la implementación y la configuración regional. Con la configuración de sensibilidad predeterminada, el comparador considera las diferencias de mayúsculas y minúsculas, pero el orden específico de apple, Apple y APPLE varía.

Diferentes configuraciones regionales tienen diferentes convenciones de orden de mayúsculas y minúsculas predeterminadas. Algunas configuraciones regionales tradicionalmente colocan primero las letras minúsculas, mientras que otras colocan primero las letras mayúsculas. Confiar en el comportamiento predeterminado produce resultados inconsistentes en diferentes entornos.

Colocar letras mayúsculas primero con caseFirst upper

Establecer caseFirst: "upper" asegura que las letras mayúsculas siempre aparezcan antes que sus equivalentes en minúsculas en los resultados ordenados.

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

El comparador ordena alfabéticamente por letra base primero, luego aplica el orden de mayúsculas y minúsculas dentro de cada grupo. Entre las palabras que comienzan con a, Apple viene antes que apple. Entre las palabras que comienzan con b, Banana viene antes que banana.

Este orden es útil al mostrar listas donde los nombres propios o títulos en mayúsculas deben aparecer de forma prominente antes que los sustantivos comunes.

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

Los nombres en mayúsculas aparecen antes que las versiones en minúsculas, lo que facilita distinguir los nombres propios de las palabras comunes en listas mixtas.

Colocar letras minúsculas primero con caseFirst lower

Establecer caseFirst: "lower" asegura que las letras minúsculas siempre aparezcan antes que sus equivalentes en mayúsculas en los resultados ordenados.

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

El comparador ordena alfabéticamente primero, luego coloca las versiones en minúsculas antes que las versiones en mayúsculas dentro de cada grupo alfabético.

Este orden coincide con las convenciones donde el texto en minúsculas se considera más estándar o neutral, con las mayúsculas reservadas para énfasis o casos especiales.

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

Las etiquetas en minúsculas aparecen primero, lo cual es útil cuando las minúsculas representan la forma canónica y las versiones en mayúsculas son variaciones menos comunes.

Usar caseFirst false para el comportamiento predeterminado de la configuración regional

Establecer caseFirst: "false" (el valor de cadena) solicita explícitamente el orden de mayúsculas y minúsculas predeterminado de la configuración regional. Esto produce el mismo resultado que omitir la opción por completo.

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

El orden de salida depende de lo que la configuración regional considere estándar. Algunas configuraciones regionales definen mayúsculas primero, otras definen minúsculas primero, y algunas tratan las cadenas que difieren en mayúsculas como iguales.

Esta opción es útil cuando deseas dejar explícito que estás usando los valores predeterminados de la configuración regional en lugar de omitir accidentalmente una elección de configuración.

Cuándo caseFirst no tiene efecto

La opción caseFirst solo afecta la comparación cuando la configuración de sensibilidad permite que las diferencias de mayúsculas y minúsculas importen. Con sensitivity: "base" o sensitivity: "accent", las diferencias de mayúsculas se ignoran por completo, haciendo que la opción caseFirst sea irrelevante.

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)

Con sensibilidad base, el comparador trata las tres cadenas como iguales. La opción caseFirst no tiene efecto porque las mayúsculas no se consideran en absoluto. El algoritmo de ordenamiento preserva el orden original de los elementos iguales (ordenamiento estable), por lo que la salida coincide con el orden de entrada.

Para que caseFirst tenga efecto, usa sensitivity: "case" o sensitivity: "variant" (el predeterminado).

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

Con sensibilidad variant (que considera todas las diferencias incluyendo mayúsculas), la opción caseFirst determina el orden de estas cadenas con variación de mayúsculas.

Ordenar nombres con orden de mayúsculas consistente

Al ordenar nombres de usuario u otros nombres propios, un orden de mayúsculas consistente garantiza resultados predecibles en toda tu aplicación.

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

El comparador coloca los nombres capitalizados antes de las versiones en minúsculas. Este ordenamiento facilita ver nombres propios versus palabras comunes en conjuntos de datos mixtos.

Ordenar nombres de archivos con orden de mayúsculas controlado

Los sistemas de archivos tienen diferentes comportamientos de sensibilidad a mayúsculas y minúsculas. Algunos tratan las mayúsculas y minúsculas como iguales, otros las tratan como diferentes. El ordenamiento explícito de mayúsculas garantiza que tus listas de archivos ordenadas coincidan con las expectativas del usuario independientemente del sistema de archivos subyacente.

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

Las versiones en minúsculas aparecen primero, coincidiendo con la convención donde los nombres de archivos en minúsculas son más estándar en sistemas tipo Unix.

Combinar caseFirst con comparación numérica

La opción caseFirst funciona junto con otras opciones de comparación como numeric. Puedes ordenar cadenas con números incrustados mientras controlas el orden de mayúsculas.

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

El comparador aplica comparación numérica para las porciones de números y ordenamiento de mayúsculas para las porciones de letras. Los elementos se ordenan primero por valor numérico (1, 2, 10), luego por mayúsculas dentro de cada grupo numérico.

Usar la clave de extensión Unicode para caseFirst

La opción caseFirst también se puede establecer mediante una extensión Unicode en el identificador de localización usando la clave kf. Los valores de extensión son upper, lower y 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']

La cadena de localización en-US-u-kf-upper especifica inglés estadounidense con ordenamiento de mayúsculas primero. Esto produce el mismo resultado que pasar { caseFirst: 'upper' } en el objeto de opciones.

Cuando tanto la extensión Unicode como el objeto de opciones especifican caseFirst, el objeto de opciones tiene precedencia.

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

El objeto de opciones especifica caseFirst: 'lower', que anula la extensión kf-upper en la cadena de localización. El comparador utiliza ordenamiento de minúsculas primero.

Verificar qué valor de caseFirst está usando un comparador

El método resolvedOptions() devuelve las opciones reales que el comparador está usando, incluida la configuración de caseFirst.

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

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

Esto es útil para depurar o verificar que tu comparador tenga la configuración esperada, especialmente al combinar extensiones Unicode con objetos de opciones.

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

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

Las opciones resueltas reflejan la configuración de la extensión Unicode cuando ningún objeto de opciones la anula.

Cuándo usar cada valor de caseFirst

Usa caseFirst: "upper" cuando:

  • Quieras que los nombres propios o títulos aparezcan antes que las palabras comunes
  • La convención de tu aplicación trate el texto en mayúsculas como más significativo
  • Estés ordenando nombres donde las versiones en mayúsculas son canónicas

Usa caseFirst: "lower" cuando:

  • Quieras que el texto en minúsculas aparezca primero como la forma estándar
  • La convención de tu aplicación trate las minúsculas como predeterminadas y las mayúsculas como especiales
  • Estés ordenando identificadores técnicos donde las minúsculas son más comunes

Usa caseFirst: "false" cuando:

  • Quieras seguir las convenciones específicas de la configuración regional
  • El orden de las cadenas que difieren en mayúsculas/minúsculas no importe para tu aplicación
  • Quieras dejar explícito que estás usando los valores predeterminados en lugar de omitir accidentalmente la opción