Natürliche Art von alphanumerischen Zeichenfolgen in JavaScript

Lesezeit: 7 Minuten

Benutzeravatar von ptrn
ptrn

Ich suche nach der einfachsten Möglichkeit, ein Array zu sortieren, das aus Zahlen und Text und einer Kombination davon besteht.

Z.B,

'123asd'
'19asd'
'12345asd'
'asd123'
'asd12'

verwandelt sich in

'19asd'
'123asd'
'12345asd'
'asd12'
'asd123'

Dies wird in Kombination mit der Lösung einer anderen Frage verwendet, die ich hier gestellt habe.

Die Sortierfunktion an sich funktioniert, was ich brauche, ist eine Funktion, die sagen kann, dass ’19asd’ kleiner als ‘123asd’ ist.

Ich schreibe dies in JavaScript.

Ich suche eine Funktion zur natürlichen Sortierung.

  • siehe auch How do you do string comparison in JavaScript? auf stackoverflow.com/questions/51165/…

    – Adriano

    26. September 2014 um 12:19 Uhr

  • Die ursprüngliche Frage wurde 2010 gestellt, also wäre es nicht überraschend 🙂

    – ptrn

    23. Juli 2015 um 21:32 Uhr

  • Mögliches Duplikat von How to sort strings in JavaScript

    – Feeela

    28. August 2018 um 11:35 Uhr

  • @feeela Das ist keine natürliche Sorte

    – Bergi

    13. Januar 2022 um 9:01 Uhr

Benutzeravatar von frodo2975
frodo2975

Dies ist jetzt in modernen Browsern möglich GebietsschemaVergleichen. Durch das Passieren der numeric: true Option, erkennt es Zahlen intelligent. Sie können Groß- und Kleinschreibung beachten sensitivity: 'base'. Es wurde in Chrome, Firefox und getestet InternetExplorer 11.

Hier ist ein Beispiel. Es kehrt zurück 1was bedeutet, dass 10 nach 2 kommt:

'10'.localeCompare('2', undefined, {numeric: true, sensitivity: 'base'})

Für die Leistung beim Sortieren einer großen Anzahl von Zeichenfolgen der Artikel sagt:

Beim Vergleichen einer großen Anzahl von Zeichenfolgen, wie z. B. beim Sortieren großer Arrays, ist es besser, ein Intl.Collator-Objekt zu erstellen und die von seiner Vergleichseigenschaft bereitgestellte Funktion zu verwenden.

var collator = new Intl.Collator(undefined, {numeric: true, sensitivity: 'base'});
var myArray = ['1_Document', '11_Document', '2_Document'];
console.log(myArray.sort(collator.compare));

  • Wenn Sie ein Array von Objekten sortieren möchten, können Sie auch den Collator verwenden: codepen.io/TimPietrusky/pen/rKzoGN

    – TimPietrusky

    15. Juni 2018 um 20:45 Uhr

  • Um den obigen Kommentar zu verdeutlichen: „Wenn das locales-Argument nicht angegeben oder nicht definiert ist, wird das Standardgebietsschema der Laufzeitumgebung verwendet.“

    – gkiely

    28. Juli 2019 um 1:28 Uhr

  • @frodo2975 Hier, was ist hier ein undefinierter Parameter … was ist der Zweck?

    – Jayden

    28. Februar 2022 um 6:15 Uhr

  • @Jayden Wir übergeben undefined, um zu vermeiden, dass ein Gebietsschema angegeben werden muss. Es wird das Standardgebietsschema des Browsers verwendet.

    – frodo2975

    2. März 2022 um 20:32 Uhr

Benutzeravatar von D0rm1nd0
D0rm1nd0

Wenn Sie ein Array von Objekten haben, können Sie es so machen:

myArrayObjects = myArrayObjects.sort(function(a, b) {
  return a.name.localeCompare(b.name, undefined, {
    numeric: true,
    sensitivity: 'base'
  });
});

var myArrayObjects = [{
    "id": 1,
    "name": "1 example"
  },
  {
    "id": 2,
    "name": "100 example"
  },
  {
    "id": 3,
    "name": "12 example"
  },
  {
    "id": 4,
    "name": "5 example"
  },

]

myArrayObjects = myArrayObjects.sort(function(a, b) {
  return a.name.localeCompare(b.name, undefined, {
    numeric: true,
    sensitivity: 'base'
  });
});
console.log(myArrayObjects);

kennebecs Benutzeravatar
kennebec

Um Werte zu vergleichen, können Sie eine Vergleichsmethode verwenden.

function naturalSorter(as, bs){
    var a, b, a1, b1, i= 0, n, L,
    rx=/(\.\d+)|(\d+(\.\d+)?)|([^\d.]+)|(\.\D+)|(\.$)/g;
    if(as=== bs) return 0;
    a= as.toLowerCase().match(rx);
    b= bs.toLowerCase().match(rx);
    L= a.length;
    while(i<L){
        if(!b[i]) return 1;
        a1= a[i],
        b1= b[i++];
        if(a1!== b1){
            n= a1-b1;
            if(!isNaN(n)) return n;
            return a1>b1? 1:-1;
        }
    }
    return b[i]? -1:0;
}

Aber um das Sortieren eines Arrays zu beschleunigen, manipulieren Sie das Array vor dem Sortieren, sodass Sie Kleinbuchstaben und den regulären Ausdruck nur einmal konvertieren müssen, anstatt in jedem Schritt durch die Sortierung.

function naturalSort(ar, index){
    var L= ar.length, i, who, next, 
    isi= typeof index== 'number', 
    rx=  /(\.\d+)|(\d+(\.\d+)?)|([^\d.]+)|(\.(\D+|$))/g;
    function nSort(aa, bb){
        var a= aa[0], b= bb[0], a1, b1, i= 0, n, L= a.length;
        while(i<L){
            if(!b[i]) return 1;
            a1= a[i];
            b1= b[i++];
            if(a1!== b1){
                n= a1-b1;
                if(!isNaN(n)) return n;
                return a1>b1? 1: -1;
            }
        }
        return b[i]!= undefined? -1: 0;
    }
    for(i= 0; i<L; i++){
        who= ar[i];
        next= isi? ar[i][index] || '': who;
        ar[i]= [String(next).toLowerCase().match(rx), who];
    }
    ar.sort(nSort);
    for(i= 0; i<L; i++){
        ar[i]= ar[i][1];
    }
}

  • Würde das in meinem Fall funktionieren, wenn das innere Array die Reihenfolge des äußeren bestimmt?

    – ptrn

    10. Mai 2010 um 13:11 Uhr

  • Was ist String.prototype.tlc()? Ist das dein eigener Code oder hast du den irgendwo her? Wenn letzteres der Fall ist, verlinken Sie bitte auf die Seite.

    – Andi E

    10. Mai 2010 um 13:15 Uhr

  • Entschuldigung für den Fehler – korrigiert, danke. Wenn Sie möchten[1] und B[1] Um die Sortierung zu steuern, verwenden Sie a= String(a[1]).toLowerCase(); b= Zeichenkette(b[1]).toLowerCase();

    – kennebec

    10. Mai 2010 um 13:17 Uhr


  • Ich hatte gerade eine Liste mit Daten, die ich sortieren wollte, dachte, es sollte in der Chrome Dev Tools-Konsole einfach sein – danke für die Funktion!

    – ajh158

    12. April 2013 um 12:30 Uhr

Benutzeravatar von Stephen Quan
Stefan Quan

Stellen Sie sich eine Nummer-Null-Padding-Funktion vor n => n.padStart(8, "0") das nimmt eine beliebige Zahl und füllt sie auf, dh

  • “19” -> “00000019”
  • “123” -> “00000123”

Diese Funktion kann verwendet werden, um beim Sortieren zu helfen "19" Zeichenfolge, sodass sie vor der angezeigt wird "123" Schnur.

Lassen Sie uns eine Regex hinzufügen /\d+/g Erstellen der natürlichen Expansionsfunktion str => str.replace(/\d+/g, n => n.padStart(8, "0")) die nur Zahlenabschnitte in einer Zeichenfolge findet und sie auffüllt, dh

  • “19asd” -> “00000019asd”
  • “123asd” -> “00000123asd”

Jetzt können wir diese natürliche Erweiterungsfunktion verwenden, um die Sortierung nach natürlicher Reihenfolge zu implementieren:

const list = [
    "123asd",
    "19asd",
    "12345asd",
    "asd123",
    "asd12"
];

const ne = str => str.replace(/\d+/g, n => n.padStart(8, "0"));
const nc = (a,b) => ne(a).localeCompare(ne(b));

console.log(list.map(ne).sort()); // intermediate values
console.log(list.sort(nc)); // result

Die Zwischenergebnisse demonstriert durch list.map(ne).sort() zeigen was die ne natürliche Expansionsfunktion tut. Es implementiert das Auffüllen von Zahlen mit Nullen nur für die Zahlenteile der Zeichenfolge und lässt die Alphabetkomponenten unverändert.

[
  "00000019asd",
  "00000123asd",
  "00012345asd",
  "asd00000012",
  "asd00000123"
]

Die endgültige Version der Lösung implementiert einen natürlichen Ordnungskomparator nc umgesetzt als (a,b) => ne(a).localeCompare(ne(b)) und verwendet es in list.sort(nc) damit die Dinge richtig geordnet werden:

[
  "19asd",
  "123asd",
  "12345asd",
  "asd12",
  "asd123"
]

Juliens Benutzeravatar
Julien

Die umfassendste Bibliothek, die dies ab 2019 handhabt, scheint zu sein natürlich-orderby.

import { orderBy } from 'natural-orderby'

const unordered = [
  '123asd',
  '19asd',
  '12345asd',
  'asd123',
  'asd12'
]

const ordered = orderBy(unordered)

// [ '19asd',
//   '123asd',
//   '12345asd',
//   'asd12',
//   'asd123' ]

Es akzeptiert nicht nur Arrays von Strings, sondern kann auch nach dem Wert eines bestimmten Schlüssels in einem Array von Objekten sortieren. Es kann auch Zeichenfolgen von Währungen, Datumsangaben, Währungen und einer Reihe anderer Dinge automatisch identifizieren und sortieren.

Überraschenderweise sind es auch nur 1,6 kB, wenn es gezippt ist.

  • Obwohl nicht ausdrücklich angegeben, scheint Ihre Antwort spezifisch für Node.JS zu sein.

    – Stephen Quan

    24. August 2021 um 22:20 Uhr

  • @StephenQuan Danke – Ich aktualisiere die Antwort, um die ES6-Modulsyntax zu verwenden, die weniger NodeJS-spezifisch ist.

    – Julian

    30. August 2021 um 23:23 Uhr

Benutzeravatar von Peter Mortensen
Peter Mortensen

Aufbauend auf kennebecs Antwort und mit dem Code that Brian Huismann & David Kölle erstellt, hier ist eine modifizierte Prototyp-Sortierung für ein Array von Objekten:

//Usage: unsortedArrayOfObjects.alphaNumObjectSort("name");
//Test Case: var unsortedArrayOfObjects = [{name: "a1"}, {name: "a2"}, {name: "a3"}, {name: "a10"}, {name: "a5"}, {name: "a13"}, {name: "a20"}, {name: "a8"}, {name: "8b7uaf5q11"}];
//Sorted: [{name: "8b7uaf5q11"}, {name: "a1"}, {name: "a2"}, {name: "a3"}, {name: "a5"}, {name: "a8"}, {name: "a10"}, {name: "a13"}, {name: "a20"}]

// **Sorts in place**
Array.prototype.alphaNumObjectSort = function(attribute, caseInsensitive) {
  for (var z = 0, t; t = this[z]; z++) {
    this[z].sortArray = new Array();
    var x = 0, y = -1, n = 0, i, j;

    while (i = (j = t[attribute].charAt(x++)).charCodeAt(0)) {
      var m = (i == 46 || (i >=48 && i <= 57));
      if (m !== n) {
        this[z].sortArray[++y] = "";
        n = m;
      }
      this[z].sortArray[y] += j;
    }
  }

  this.sort(function(a, b) {
    for (var x = 0, aa, bb; (aa = a.sortArray[x]) && (bb = b.sortArray[x]); x++) {
      if (caseInsensitive) {
        aa = aa.toLowerCase();
        bb = bb.toLowerCase();
      }
      if (aa !== bb) {
        var c = Number(aa), d = Number(bb);
        if (c == aa && d == bb) {
          return c - d;
        } else {
          return (aa > bb) ? 1 : -1;
        }
      }
    }

    return a.sortArray.length - b.sortArray.length;
  });

  for (var z = 0; z < this.length; z++) {
    // Here we're deleting the unused "sortArray" instead of joining the string parts
    delete this[z]["sortArray"];
  }
}

  • Obwohl nicht ausdrücklich angegeben, scheint Ihre Antwort spezifisch für Node.JS zu sein.

    – Stephen Quan

    24. August 2021 um 22:20 Uhr

  • @StephenQuan Danke – Ich aktualisiere die Antwort, um die ES6-Modulsyntax zu verwenden, die weniger NodeJS-spezifisch ist.

    – Julian

    30. August 2021 um 23:23 Uhr

1442280cookie-checkNatürliche Art von alphanumerischen Zeichenfolgen in JavaScript

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy