[javascript] 자바 스크립트 : 자연 숫자의 영숫자 문자열

숫자와 텍스트로 구성된 배열을 정렬하는 가장 쉬운 방법을 찾고 있습니다.

예 :

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

로 변하다

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

이것은 내가 여기서 물었던 다른 질문에 대한 해결책과 함께 사용될 입니다.

정렬 기능 자체가 작동합니다. 필요한 것은 ’19asd’가 ‘123asd’보다 작다는 말할 수있는 기능입니다.

나는 이것을 JavaScript로 작성하고 있습니다.

편집 : adormitu가 지적했듯이, 내가 찾고있는 것은 자연 정렬 기능입니다.



답변

이제 localeCompare를 사용하는 최신 브라우저에서 가능합니다. numeric: true옵션 을 전달 하면 스마트하게 숫자를 인식합니다. 을 사용하여 대소 문자를 구분할 수 있습니다 sensitivity: 'base'. Chrome, Firefox 및 IE11에서 테스트되었습니다.

다음은 예입니다. 그것은 반환 1(10)가 2 후에가는 의미 :

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

많은 수의 문자열을 정렬 할 때의 성능을 위해이 기사에서는 다음과 같이 말합니다.

큰 배열 정렬과 같이 많은 수의 문자열을 비교할 때는 Intl.Collator 객체를 만들고 compare 속성에서 제공하는 함수를 사용하는 것이 좋습니다. 문서 링크

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


답변

그래서 당신은 자연적인 정렬 이 필요 합니까?

그렇다면 David koelle의 작업을 기반으로 한 Brian Huisman의이 대본 보다 필요한 것입니다.

Brian Huisman의 솔루션이 David Koelle의 블로그에서 직접 호스팅되는 것 같습니다.


답변

값을 비교하기 위해 비교 방법을 사용할 수 있습니다.

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;
}

그러나 배열 정렬 속도를 높이려면 정렬하기 전에 배열을 조작하십시오. 따라서 정렬 단계마다 소문자 변환과 정규 표현식을 한 번만 수행하면됩니다.

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


답변

객체 배열이 있으면 다음과 같이 할 수 있습니다.

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


답변

2019 년 현재이 기능을 처리 할 수있는 가장 완벽한 기능을 갖춘 라이브러리는 당연한 것 같습니다 .

const { orderBy } = require('natural-orderby')

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

const ordered = orderBy(unordered)

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

문자열 배열뿐만 아니라 객체 배열의 특정 키 값을 기준으로 정렬 할 수도 있습니다. 또한 통화, 날짜, 통화 및 기타 여러 가지 문자열을 자동으로 식별하고 정렬 할 수 있습니다.

놀랍게도 gzipped했을 때 1.6kB에 불과합니다.


답변

다음을 변환하는 8 자리 패딩 함수를 상상해보십시오.

  • ‘123asd’-> ‘00000123asd’
  • ’19asd’-> ‘00000019asd’

채워진 문자열을 사용하여 ‘123asd’앞에 ’19asd’가 표시되도록 정렬 할 수 있습니다.

정규식 /\d+/g을 사용하여 채워야하는 모든 숫자를 찾는 데 도움이됩니다.

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

다음은이 기술을 사용한 정렬을 보여줍니다.

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

중간 결과는 natural_expand () 루틴의 기능을 보여주고 후속 natural_compare 루틴의 작동 방식을 이해합니다.

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

출력 :

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


답변

위의 @Adrien Be의 대답을 바탕으로 Brian Huisman & David koelle이 만든 코드를 사용하여 객체 배열에 대한 수정 된 프로토 타입 정렬이 있습니다.

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