2010-05-10 5 views
69

Ich suche nach dem einfachsten Weg, ein Array zu sortieren, das aus Zahlen und Text und einer Kombination von diesen besteht.Javascript: natürliche Art von alphanumerischen Zeichenketten

z.

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

verwandelt sich in

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

Dies wird mit der Lösung another question I've asked here in Kombination verwendet werden.

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

Ich schreibe dies in JavaScript.

Edit: als adormitu wies darauf hin, was ich suche, ist eine Funktion für natürliche

Sortierung
+0

siehe auch 'How do you do String-Vergleich in JavaScript' auf http://stackoverflow.com/questions/51165?/How-Do-You-Do-String-Vergleich-in-Javascript –

+1

Die ursprüngliche Frage wurde im Jahr 2010 gestellt, so wäre es nicht überraschend :) – ptrn

Antwort

102

Dies ist nun möglich, in modernen Browsern localeCompare. Wenn Sie die Option numeric: true übergeben, werden Nummern intelligent erkannt. Sie können die Groß-/Kleinschreibung beachten, indem Sie sensitivity: 'base' verwenden. Getestet in Chrome, Firefox und IE11.

Hier ist ein Beispiel. Es gibt 1, was bedeutet, 10 geht nach dem 2:

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

Für Leistung, wenn eine große Anzahl von Zeichenketten sortieren, der Artikel sagt:

Beim Vergleich einer großen Anzahl von Strings, wie bei der Sortierung groß Arrays ist es besser, ein Intl.Collator-Objekt zu erstellen und die Funktion zu verwenden, die von seiner Eigenschaft compare bereitgestellt wird.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare

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

upvote für einen modernen One-Liner +1! – A1rPun

+1

Super, nette Annäherung –

+1

Ehrfürchtig, Sie lösten mein Problem. Vielen Dank –

38

So benötigen Sie einen natürliche Art?

Wenn ja, dann vielleicht this script by Brian Huisman based on David koelle's work wäre was Sie brauchen.

Es ist wie Brian Huisman Lösung scheint nun direkt auf David Koelle Blog hosted:

+0

Korrekte, natürliche Art ist, was ich suche. Ich werde auf den Link, den Sie gesendet haben, nachsehen, danke – ptrn

+0

Dies hat sicherlich den Trick getan. Vielen Dank! – ptrn

+0

Das ist eine sehr unnatürliche Art. Es erzeugt keine alphabetische Sortierung. – tchrist

17

Werte vergleichen Sie einen Vergleich Methoden-

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; 
} 
verwenden können

Aber für die Geschwindigkeit in sorti ng ein Array, rig das Array vor der Sortierung, , so dass Sie nur Kleinbuchstaben Konvertierungen und den regulären Ausdruck einmal statt in jedem Schritt durch die Sortierung tun müssen.

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]; 
    } 
} 
+0

würde dies in meinem Fall funktionieren, mit dem inneren Array, das die Reihenfolge des äußeren entscheidet? – ptrn

+0

Was ist 'String.prototype.tlc()'? Ist das dein eigener Code oder hast du ihn irgendwo gefunden? Wenn Letzteres, bitte Link zu der Seite. –

+0

Entschuldigung wegen des Fehlers korrigiert, danke. Wenn Sie möchten, dass [1] und b [1] die Sortierung steuern, verwenden Sie a = String (a [1]). ToLowerCase(); b = Zeichenfolge (b [1]).toLowerCase(); – kennebec

0

Aufbauend auf @Adrien von oben und mit dem Code Seien Sie antworten, dass Brian Huisman & David koelle erstellt, hier ist ein modifizierter Prototyp für eine Reihe von Objekten Sortierung:

//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"]; 
    } 
} 
0

Abbildung einer 8-stelligen Füllfunktion, die "123asd" und "19asd" in "00000123asd" bzw. "00000019asd" umwandelt. Die Verwendung dieser Versionen von Strings wird uns helfen, '19asd' vor '123asd' zu sortieren.

können wir den regulären Ausdruck verwenden /\d+/g zu helfen, alle Zahlen zu finden, die aufgefüllt werden müssen:

str.replace(/\d+/g, pad) 

Nachstehend demonstriert mit dieser Technik Sortierung:

var list = [ 
 
    '123asd', 
 
    '19asd', 
 
    '12345asd', 
 
    'asd123', 
 
    'asd12' 
 
]; 
 

 
function pad(n) { return ("00000000" + n).substr(-8); } 
 
function natural_expand(a) { return a.replace(/\d+/g, pad) }; 
 
function natural_compare(a, b) { 
 
    return natural_expand(a).localeCompare(natural_expand(b)); 
 
} 
 

 
console.log(list.map(natural_expand).sort()); // intermediate values 
 
console.log(list.sort(natural_compare)); // result

Die Zwischenergebnisse zeigen, was die natürliche_expand() Routine macht und gibt Ihnen eine Verständnis davon, wie die nachfolgende natural_compare Routine funktioniert:

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

Ausgänge:

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