[JavaScript] Natural String Sorting with localeCompare

目次

Overview

When you sort an array using the default sort method, lists containing a mix of uppercase and lowercase English words often result in an unexpected order. For example, “Zebra” might appear before “apple.” This happens because computers determine the order based on character codes like ASCII. To sort strings in a natural dictionary order that humans use, you should employ the localeCompare method. This article demonstrates how to correctly sort a list of names or locations using this method to handle case sensitivity and natural language rules.

Specifications

localeCompare Method

This method compares a reference string with a given string and returns a numeric value representing the sort order.

MethodMeaningReturn ValueBehavior in sort
strA.localeCompare(strB)Compares strA and strB in dictionary order.Negative (-1)Places strA before strB
Positive (1)Places strA after strB
0No change in order
  • Input: The string to be compared.
  • Output: A numeric value (-1, 0, or 1) indicating the sort order.

Basic Usage

Difference Between Default sort and localeCompare

By default, uppercase letters (A-Z) take priority over lowercase letters (a-z). Using localeCompare ignores this technical priority and follows the actual alphabetical order.

const members = ['mori', 'Hayashi', 'kogi'];

// 1. Default sort (Uppercase takes priority)
members.sort();
console.log(members); 
// ["Hayashi", "kogi", "mori"] - "H" comes before "k" in character codes

// 2. Using localeCompare (Dictionary order)
members.sort((a, b) => a.localeCompare(b));
console.log(members); 
// ["Hayashi", "kogi", "mori"] - Alphabetical A->Z regardless of case

Full Code (HTML / JAVASCRIPT)

This demo manages a list of location names. Even if the input data has inconsistent capitalization, the system sorts them correctly in alphabetical order.

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Location List Sort</title>
    <style>
        .sort-panel {
            font-family: 'Segoe UI', sans-serif;
            max-width: 500px;
            padding: 20px;
            border: 1px solid #ccc;
            border-radius: 8px;
            background-color: #f9f9f9;
        }
        .btn-group {
            margin-bottom: 15px;
            display: flex;
            gap: 10px;
        }
        button {
            padding: 10px 15px;
            cursor: pointer;
            border: 1px solid #999;
            background-color: #fff;
            border-radius: 4px;
        }
        button:hover { background-color: #eee; }
        
        .list-area {
            background: white;
            border: 1px solid #ddd;
            padding: 10px;
            min-height: 100px;
        }
        ul { margin: 0; padding-left: 20px; }
        li { padding: 4px 0; border-bottom: 1px dashed #eee; }
        .note { font-size: 0.85rem; color: #666; margin-bottom: 10px; }
    </style>
</head>
<body>

<div class="sort-panel">
    <h3>Location Name Sorting</h3>
    <p class="note">Data: ['mori', 'Hayashi', 'kogi', 'Oki', 'nakabayashi']</p>
    
    <div class="btn-group">
        <button id="btn-default">Default Sort (ASCII)</button>
        <button id="btn-locale">localeCompare (Dictionary)</button>
    </div>

    <div class="list-area">
        <ul id="location-list">
            </ul>
    </div>
</div>

<script src="location_sort.js"></script>
</body>
</html>

JavaScript

/**
 * Location Sorting Script
 * Comparing logic differences for string arrays
 */

// 1. Data to be sorted
// Intentionally mixing uppercase and lowercase
let locations = ['mori', 'Hayashi', 'kogi', 'Oki', 'nakabayashi'];

// DOM elements
const listElement = document.getElementById('location-list');
const btnDefault = document.getElementById('btn-default');
const btnLocale = document.getElementById('btn-locale');

/**
 * Function to render the list
 */
const renderList = () => {
    listElement.innerHTML = '';
    locations.forEach(loc => {
        const li = document.createElement('li');
        li.textContent = loc;
        listElement.appendChild(li);
    });
};

/**
 * Default sorting (Character code order)
 * Uppercase (A-Z) comes before lowercase (a-z)
 */
const sortDefault = () => {
    locations.sort();
    renderList();
};

/**
 * Sorting using localeCompare (Dictionary order)
 * Alphabetical order without case sensitivity
 */
const sortLocale = () => {
    locations.sort((a, b) => {
        // Compare using natural language rules
        return a.localeCompare(b);
    });
    renderList();
};

// Initial display
renderList();

// Event settings
btnDefault.addEventListener('click', sortDefault);
btnLocale.addEventListener('click', sortLocale);

Custom Points

When sorting Japanese text, you should specify ‘ja’ as the locale code in the second argument to ensure correct handling of hiragana, katakana, and kanji. For example, list.sort((a, b) => a.localeCompare(b, 'ja')). Note that it cannot determine the specific reading of kanji, so phonetic data is required for perfect results. If you need to sort strings containing numbers, such as “File1” and “File10,” you can enable numeric sorting by passing an options object as the third argument like a.localeCompare(b, undefined, { numeric: true }).

Important Notes

While localeCompare is highly functional, it can be slower than simple comparison operators when sorting extremely large datasets of tens of thousands of items. For most common lists, the performance difference is negligible, but keep this in mind for critical performance scenarios. Additionally, since this involves the sort method, it modifies the original array directly. If you need to keep the original data, create a copy first using the spread syntax like [...locations].sort().

Advanced Usage

Sorting in Descending Order

To reverse the order, simply swap the reference string and the argument in the localeCompare call.

// Ascending (A -> Z)
locations.sort((a, b) => a.localeCompare(b));

// Descending (Z -> A)
locations.sort((a, b) => b.localeCompare(a));

Summary

You should always use the localeCompare method when arranging text data like user names or product titles in a way that is easy for humans to read. The default sort method follows computer-centric logic where uppercase letters take precedence, which can feel unnatural in a UI. Choosing the human-friendly dictionary order with localeCompare is a primary step toward building a more intuitive and user-friendly interface.

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次