regulares - Javascript: tipo natural de cadenas alfanuméricas
validar caracteres especiales javascript (5)
¿Entonces necesitas un tipo natural ?
Si es así, quizás este guión de Brian Huisman basado en el trabajo de David Koelle sea lo que necesites.
Parece que la solución de Brian Huisman ahora está alojada directamente en el blog de David Koelle:
Estoy buscando la manera más fácil de ordenar una matriz que consta de números y texto, y una combinación de estos.
P.ej
''123asd''
''19asd''
''12345asd''
''asd123''
''asd12''
se convierte en
''19asd''
''123asd''
''12345asd''
''asd12''
''asd123''
Esto se usará en combinación con la solución a otra pregunta que hice aquí .
La función de clasificación en sí funciona, lo que necesito es una función que pueda decir que ''19asd'' es más pequeño que ''123asd''.
Estoy escribiendo esto en JavaScript.
Editar: como lo señaló adormitu , lo que estoy buscando es una función para la clasificación natural
Esto ahora es posible en navegadores modernos usando localeCompare. Al pasar la opción numeric: true
, reconocerá los números inteligentemente. Puede hacer mayúsculas y minúsculas utilizando la sensitivity: ''base''
. Probado en Chrome, Firefox e IE11.
Aquí hay un ejemplo. Devuelve 1
, lo que significa que 10 va después de 2:
''10''.localeCompare(''2'', undefined, {numeric: true, sensitivity: ''base''})
Para el rendimiento cuando se ordenan grandes cantidades de cadenas, el artículo dice:
Al comparar grandes cantidades de cadenas, como en la ordenación de matrices grandes, es mejor crear un objeto Intl.Collator y utilizar la función proporcionada por su propiedad de comparación. Enlace de documentos
var collator = new Intl.Collator(undefined, {numeric: true, sensitivity: ''base''});
var myArray = [''1_Document'', ''11_Document'', ''2_Document''];
console.log(myArray.sort(collator.compare));
Imagine una función de relleno de 8 dígitos que transforma:
- ''123asd'' -> ''00000123asd''
- ''19asd'' -> ''00000019asd''
Podemos usar las cadenas acolchadas para ayudarnos a ordenar ''19asd'' para que aparezca antes de ''123asd''.
Use la expresión regular //d+/g
para ayudar a encontrar todos los números que deben rellenarse:
str.replace(//d+/g, pad)
A continuación se muestra la clasificación usando esta técnica:
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
Los resultados intermedios muestran lo que hace la rutina natural_expand () y le da una comprensión de cómo funcionará la siguiente rutina natural_compare:
[
"00000019asd",
"00000123asd",
"00012345asd",
"asd00000012",
"asd00000123"
]
Productos:
[
"19asd",
"123asd",
"12345asd",
"asd12",
"asd123"
]
Para comparar valores, puede usar un método de comparación:
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;
}
Pero para agilizar la ordenación de una matriz, arme la matriz antes de ordenar, por lo que solo tiene que hacer conversiones en minúsculas y la expresión regular una vez en lugar de en cada paso de la ordenación.
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];
}
}
Sobre la base de la respuesta de @Adrien Be y utilizando el código creado por Brian Huisman y David Koelle , aquí hay una clasificación de prototipo modificado para una variedad de objetos:
//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"];
}
}