【超簡単】正規表現を使った「数字を含む文字列」の配列内ソート

# はじめに
みなさんは`['test1', 'test4', 'test3', 'test2']`の様な、数字を含む文字列の配列がある場合、どの様に並び替えようとしますか？数字を昇順に沿って並べ替える場合、以下の様な結果を期待しますよね。`['test1', 'test2', 'test3', 'test4']`

`Split`メソッドを使って、連想配列(オブジェクト)を作りそこから処理を回しますか？

私は実際、そういう風に書いていました。それで大体<font color="red">約15行</font>のほどのコード。

```index.js
function order(words){
//   var arry = [];
  words = words.split(" ").map(el => el.split(""));
  var obj = {};
  for (var i = 0; i<words.length;i++){
    var key = words[i].find(el => el>0);
    obj[key] = words[i];
  }
  var arry = Object.values(obj).map(el => el.join(""));
  
  if (arry.length > 0) {
    return arry.join(" ")
  } else {
    return "";
  }
}
```

はい、なんとも冗長な汚いコードです。

そんな中、とある場所で**美しいコード**を発見しました。それは、`正規表現`を使う方法！たったの<font color="red">5行</font>で書かれていました lol

正規表現って何？と思われた方はこちらをどうぞ。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Regular_Expressions


今まであまり触れてくることのなかった`正規表現`。もちろん他のメソッドを駆使した書き方でも問題はありませんが、コードを短く美しく書き直せると知った感動はいいですよねー。

その過程で学んだことをまとめたいと思います。


# 使うメソッド
[`match`](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/match)
[`sort`](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)
`正規表現`の`\d`

はい、この３つだけです。シンプル〜。
さ、一つ一つ見て行きましょう！
# 練習(前置き)
実際に検証ツールのコンソール画面などを使ってやってみましょう！
## `match`メソッドと`\d`を使って文字列から数字の取得
```index.js
var str = 'test1test2test3test4'
var num = str.match(/\d/);
console.log(arry); //結果："1"
```
`match`メソッドと正規表現の`/\d/`を組み合わせることで、文字列に含まれる最初の数字を取得することができます。ちなみに取得したデータは`数値`ではなく`文字列`ですので、このまま計算に使うと予期せぬ結果が返ってきますのでご注意を。

```index.js
var str = 'test1test2test3test4'
var num = str.match(/\d/);
console.log(num + 1); //結果：'11' (文字列に足しているため)
console.log(+num + 1); //結果：2 (数値化して処理している)
```

## `g`フラグを追加して文字列から全数字を取得

```index.js
var str = 'test1test2test3test4'
var arry = str.match(/\d/g); //←'g'フラグを追加
console.log(arry); //結果：['1','2','3','4']
```
`g`フラグをつけることで、<font color="red">マッチする全てを含む配列</font>を返してくれます。ここのポイントは、`配列`を返すということです。これとてもすごくないですか？単純に`g`をつけるだけで配列まで作ってくれるんですよ！他のメソッドも組み合わせていけばかなりいろいろなことができちゃいますね。

## `sort`メソッドで並び替え

```index.js
var arry = [7, 6, 4, 1, 2]
arry.sort();
console.log(arry); // 結果：[1, 2, 4, 6, 7]
```
配列内を比較して、小さい順に並び替えてくれるメソッドです。とても便利ですよね！しかし、このメソッドも気をつけなければならないポイントがあります。それは、要素はそれぞれの<font color="red">**文字列に変換したものを比較**</font>して<font color="red">**辞書 (あるいは電話帳。数的でない) 順**</font>にソートされるという点です。どういうことでしょうか？

先ほどは１桁の数字のみの配列でしたので問題ありませんでしたが、２桁の数字が絡んでくると問題が出て来ます。つまりこういうことです。↓↓

```index.js
var arry = [7, 16, 4, 1, 2]
arry.sort();
console.log(arry); // 結果：[1, 16, 2, 4, 7]
```
あれ、`16`が`2`の前に来てしまっています！これが先ほど言った`文字列に変換したものを比較して辞書順にソートされる`ということです。つまり`16`の２桁目が`1`であるが故に、`2`という値よりも先に来ると判断されてしまうのです。

数値として判断して、ソートしたい場合はこのままでは思う様に並び替えることができません。そこで必要になってくるのが、`比較関数`です。
##`sort`メソッドと`比較関数`をセットで使う
比較処理を行う関数を定義することで、`sort`メソッドがより使いやすくなります。比較関数はこの様な形です。

```index.js
function (a, b) {
  return a - b;
}
```
とてもシンプルですね！きちんと`>`や`<`を使って条件分岐をしてから`return`する書き方もありますが、コードが冗長になりますので、こちらの書き方を覚えておくだけでいいと思います。関数に入ってくる`a`と`b`を比較して、<font color="red">**昇順**</font>に並べ替えてくれます。`a - b`の部分を`b - a`と書き換えると<font color="red">**降順**</font>になります。

それでは、この比較関数を先ほどの`sort`メソッドの中に入れてみましょう。

```index.js
var arry = [7, 16, 4, 1, 2]
arry.sort(function(a, b){
    return a - b
});
console.log(arry); //結果：[1, 2, 4, 7, 16]


// ちなみにArrow関数で書くとfunctionと書かなくて済む
// arry.sort((a, b) => {
//     return a - b
// });
// console.log(arry); //結果：[1, 2, 4, 7, 16]
```
するときちんと昇順に並び替えができています！しかしこれはシンプルな`数値`の配列に限ります。

では、これらのメソッドを組み合わせて、いよいよ`「数字を含む文字列」の配列内ソート`をしてみましょう！

# 実践
「数字を含む文字列」の配列内ソートにおいて必要となるのは`match`メソッド+正規表現の`/\d/`+`sort`メソッドの掛け合わせです。

```index.js
var words = ['test1', 'test7', 'test4', 'test2'];
words.sort(function(a,b){
   return a.match(/\d/) - b.match(/\d/);
}); 
console.log(words); // 結果：['test1', 'test2', 'test4', 'test7'];
```
配列に対して`sort`メソッドをかけ、その中の比較関数で`match`メソッドと正規表現`/\d/`を利用しています。それだけで、配列内の各文字列内の数値を比較して並べ替えています。

```index.js
var words = ['a1aaa', 'd4ddd', 'bbb2b', 'ccc3cc'];
words.sort(function(a,b){
   return a.match(/\d/) - b.match(/\d/);
}); 
console.log(words); // 結果：['a1aaa', 'bbb2b', 'ccc3cc', 'd4ddd'];
```
数字が文字列の途中であっても、きちんと並べ替えてくれますね。

しかし、こちらは文字列をそのまま比較しておりますので、もちろん`辞書順`での比較になります。つまり、２桁の数字を含む場合は、以下のような結果になってしまいます。

```index.js
var words = ['a1aaa', 'd16ddd', 'bbb2b', 'ccc3cc'];
words.sort(function(a,b){
   return a.match(/\d/) - b.match(/\d/);
}); 
console.log(words); // 結果：["a1aaa", "d16ddd", "bbb2b", "ccc3cc"];
```

この問題を解決するために使うのが、`/\d+/`です。`+`をつけることで、直前の文字の 1 回以上の繰り返しにマッチします。([hogefuga]((https://qiita.com/hogefuga)さんのアドバイスでわかりました）
)さんのコメントに感謝です）

こちらを使うことで、見事に文字列に含まれた数字の値順に並び変わってくれます。

```index.js
var words = ['a1aaa', 'd16ddd', 'bbb2b', 'ccc3cc'];
words.sort(function(a,b){
   return a.match(/\d+/) - b.match(/\d+/);
}); 
console.log(words); // 結果：["a1aaa", "bbb2b", "ccc3cc","d16ddd"];
```

# 最後に

`正規表現`パターンは他にもたくさんあります。私も駆け出しの身ですので、まだまだ至らない部分はありますが、今回は正規表現の便利さにビックリしました。少しプログラミングに慣れて来たら、`正規表現`を勉強することで、活用の場が広がって行きそうです。

# 参考
[正規表現の基本](https://qiita.com/sea_ship/items/7c8811b5cf37d700adc4)
[サルにもわかる正規表現入門](http://www.mnet.ne.jp/~nakama/)
[正規表現-JavaScript](https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Regular_Expressions)