問題解決-ファイル名のソート


https://programmers.co.kr/learn/courses/30/lessons/17686#qna

ソート[3]ファイル名


問題の説明
ファイル名のソート
3回のコードテストと2回の面接に合格し、長時間の点字公開に無事合格し、ココア社に入社した武智はファイルストレージサーバの管理を担当した.
リポジトリ・サーバには、プログラムのすべての過去のバージョンが含まれているため、名前順のファイル・リストは表示しにくい.ファイルを名前でソートするとver-10が作成されます.zipはver-9です.zipより先に表示されるからです.
バージョン番号を除いて、数値を含むファイルリストは多くの点で管理しにくい.例えば、ファイルリストが[「img 12.png」、「img 10.png」、「img 2.png」、「img 1.png」、「img 10.png」、「img 12.png」、「img 2.png」の場合、数字順の[「img 1.png」、「img 2.png」、「img 10.png」、「img 12.png」、「img 12.png」、「img 12.png」の場合、自然な順序で並べられたファイルリストはずっと多い.
無知は、単純な文字コード順ではなく、ファイル名に含まれる数字に基づいてソート機能をリポジトリ管理プログラムで実現することを決定します.
ソース・ファイル・リポジトリに格納されるファイル名は、英字大文字、数字、スペース(")、ピリオド(".")、マイナス記号("-")で構成されています.ファイル名はアルファベットで始まり、1つ以上の数字が含まれます.
ファイル名は、HEAD、NUMBER、TAILの3つの部分で構成されています.
HEADは、少なくとも1文字以上の数字以外の文字で構成されています.
NUMBERは、1文字から最大5文字までの連続数字で構成され、前は0であってもよい.0から999999までの数字は、00000や0101などであってもよい.
TAILは残りの部分で、数字が再表示される可能性があり、文字がない可能性があります.
ファイル名HEAD NUMBER TAIL
foo9.txt foo 9 .txt
foo010bar020.zip foo 010 bar020.zip
F-15 F-15(空の文字列)
ファイル名を3つのセクションに分けて、次の基準に従ってファイル名をソートします.
ファイル名は、まずHEAD部分に準じてアルファベット順に並べます.この場合、文字列の比較では大文字と小文字は区別されません.MUZIとMUZI,MUZIはソート時に同じ順序で処理する.
ファイル名のHEAD部分が大文字と小文字の違いを除いて同じである場合、NUMBERの数値順に並べ替えられます.9<10<0011<012<13<014の順に並べます.数値の前の0は無視され、012と12はソート時に同じ値に処理されます.
2つのファイルのHEAD部分とNUMBERの数字が同じ場合、元の入力の順序は維持されます.MUZI01.ZipとMuzi 1pngが入力として入力されると、ソート後も入力時に与えられた2つのファイルの順序を変更することはできません.
無知なファイル名ソートプログラムの実装を支援します.
入力フォーマット
入力として、整列ファイルを与えます.
filesは、1000個以下のファイル名を含む文字列配列です.
各ファイル名の長さは、英字大文字小文字、数字、スペース(")、ピリオド(".")、マイナス記号("-")で構成されています.ファイル名はアルファベットで始まり、1つ以上の数字が含まれます.
重複するファイル名はありませんが、大文字と小文字、または数字の最初のゼロ差を同時に与えることができます.(Muzi 1.txt、Muzi 1.txt、Muzi 001.txt、Muzi 1.TXTとともに入力できます.)
出力フォーマット
上記標準出力で並べ替えます.
I/O例
入力:["img 12.png"、"img 10.png"、"img 02.png"、"img 1.png"、"IMG 01.GIF"、"img 2.JPG"]
出力:["img 1.png"、"IMG 01.GIF"、"img 02.png"、"img 2.JPG"、"img 10.png"、"img 12.png"]
入力:["F-5 Freedom Fighter"、"B-50 Superfortress"、"A-10 ThunderboltII"、"F-14 Tomcat"]
出力:["A-10 ThunderboltII"、"B-50 Superfortress"、"F-5 Freedom Fighter"、"F-14 Tomcat"]
問題を解く
function solution(files) {
   const change = (str) => {
        let regex = /[0-9]/;
        let arr = [];
        let el = "";
        let checkNum = false;
        for (let i = 0; i<str.length; i++) {
            if(regex.test(str[i]) && !checkNum) {
                checkNum = true;
                arr.push(el)
                el = str[i]
            }
            else if (regex.test(str[i]) && checkNum) {
                el += str[i]
            }
            else if (!regex.test(str[i]) && !checkNum) {
                el += str[i]
            }
            else if (!regex.test(str[i]) && checkNum) {
                arr.push(el)
                arr.push(str.slice(i))
                return arr;
            }
        }
        arr.push(el)
        return arr;
    }
    
    files = files.sort((a,b) => {
        let ca = change(a), cb = change(b);
        let checkA = ca[0].toLowerCase(), checkB = cb[0].toLowerCase();
        if (checkA > checkB) return 1;
        else if (checkA < checkB) return -1;
        else {
            if(Number(ca[1]) === Number(cb[1])) return 0;
            else return Number(ca[1]) - Number(cb[1])
        }
    })
    return files;
}
初めて問題を解くとき、isnanを利用して多くのテストケースをしました.
「」スペースはisnanから数字に翻訳されているので、問題は間違っています.
したがって,正規表現を用いて数値のみをフィルタリングした.
文字列を置き換える関数changeが最初に作成されました.
条件は、iの1番目の文字列が数値であるが、それ以前は数値がないことです.
変数checkNumをtrueに変換し、前に収集した文字列elを配列に入れます.
文字列elをstr[i]に変換します.
次の条件は数字で、その前に数字が現れます.
この場合、elには数値文字列が追加されます.
次の条件が数値ではなく、それ以前に数値がない場合:
elに文字列を付ける.
最後の条件は数字ではありません.もし前に数字が現れたら.
この場合、el(数字文字列のみを含む)をarrに、残りのi以降の文字列をarrにすべて入れます.次にarrを返します.
最後の条件では、次の文字列が数字でない場合は、繰り返し文が終わる場合なので、繰り返し文が終わるとelをarrに入れてarrを返させます.
このように文字列を整理した後,sort()関数を用いてソートする.
最初の文字列から数字までのすべての部分について、大文字と小文字を区別しないため、すべて小文字に置き換え、昇順ソートします.
同じであれば、昇順に数字区間を並べて正解を得ることができます.