PowerShellでC#っぽいクラスを書いて楽しく文字列操作

## 概要
####こんなコードです
文字列の中から指定した正規表現にマッチした部分のみを文字色を赤に変更して出力するためのクラスをPowerShellで書きました。
<img width="600" alt="qiita_august_5.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262132/45250f00-aecd-eca1-5148-616bcf222b46.png">

#### 使用バージョン
以下のバージョンで動作確認がとれています。
Windows PowerShell 5.1.1
PowerShell 6.2.2


#### 用法
1. `InsertDlm`と`HighlightKeyword`という2つのクラスを定義する（コード詳細は次項）
2. 次の3つを引数にしてクラス`InsertDlm`からインスタンスを作成、変数`$output`に代入
    1. `$string`: 文字列全体
    2. `$keyword`: 赤文字で出力したい文字列を表す正規表現
    3. `$delimiter`: `$keyword`を赤文字にするための区切り文字（`$string`内で使用されないであろう文字を指定）
    
3. `HighlightKeyword`のメソッドを呼び出す。文字列がラテン文字を含む場合、大文字と小文字の区別をつけるときは`CaseSensitive`、つけないときは`IgnoreCase`を使用する。

4. 「3.」のメソッドを呼び出す際は次の3つを引数にする。
    1. `Case()`メソッドを呼び出して得られる値
    2. `$keyword`: `InsertDlm`の`$keyword`と同じ値を指定
    3. `$delimiter`: `HighlightKeyword`の`$delimiter`と同じ値を指定

```powershell
#手順2.
>> $test = "This is a sentence for demonstrating how these 2 classes `
are useful and informative. But if you find some mistakes or`
 simpler codes,please let me know. I'll check them immediately.`
I'm happy if these sample classes encourage you to write PowerShell classes."

>> $output = [InsertDlm]::new($test,"(,|\.)\w+","#")
#正規表現:
#| : 左右どちらかにマッチすればTrue
#\w: 任意の英数字、アンダーバー、日本語などの表意文字にマッチすればTrue
#+: 最長一致

#手順3.と手順4.

>> [HighlightKeyword]::IgnoreCase($output.IgnoreCase(),"(,|\.)\w+","#")

```
#### 実行結果
カンマのあとにスペースが抜けているのを発見できました。
<img width="550" alt="qiita_august_1.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262132/03d013c4-4175-b31f-99be-258952f97b53.png">


## クラス詳細

### InsertDlm
##### コンストラクタ
`InsertDlm(String, String, String)`
文字列の中に指定する正規表現があった場合、その前後に区切り文字を挿入するために使用する`InsertDlm`クラスのインスタンスを初期化

##### メソッド
`CaseSensitive()` : 正規表現がマッチするか判別する際、大文字と小文字を区別する
`IgnoreCase()` : 正規表現がマッチするか判別する際、大文字と小文字を区別しない

##### アプローチ
`Regex`クラス (`System.Text.RegularExpressions`) を使用し、正規表現が文字列内でマッチした場合、`Replace`メソッドを使用してマッチ部分の前後に区切り文字を挿入。

##### コード

```powershell
class InsertDlm{
    [string]$string
    [string]$keyword
    [string]$delimiter

    [string]CaseSensitive(){ 
        $dlm = $this.delimiter
        return [Regex]::Replace($this.string,"($($this.keyword))","$dlm`$1$dlm")
    }

    [string]IgnoreCase(){ 
        $dlm = $this.delimiter
        return [Regex]::Replace($this.string,"($($this.keyword))","$dlm`$1$dlm", "IgnoreCase")
    }

    InsertDlm([string]$string,[string]$keyword,[string]$delimiter){
        [string]$this.string = $string
        [string]$this.keyword = $keyword
        [string]$this.delimiter = $delimiter
    }  
}
```

##### 出力テスト

```PowerShell
>> $sample = "This is a test sentence."
>> [InsertDlm]::new($sample,"T","#").IgnoreCase() ;`
>> [InsertDlm]::new($sample,"T","#").CaseSensitive()
```
#####出力
<img width="350" alt="qiita_august_6.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262132/17c0e0f6-e59f-7bbe-486e-15d00c727333.png">



### HighlightKeyword
#####メソッド
`Output(String, String, String)` : 
文字列を区切り文字で分割し、その個々の要素に対して正規表現にマッチするか検証する。マッチしない場合は文字色をデフォルトのまま出力し、する場合は赤に変えて出力する。

#####アプローチ
`InsertDlm`で挿入した区切り文字と同じものを`HighlightKeyword`でも指定することで、文字列内にマッチするものがあれば配列内にマッチ部分だけの要素ができることになる。
パイプラインを使えば文字列の先頭から一要素ずつ判別させることができる。

#####コード
```powershell
class HighlightKeyword{
    static[void]IgnoreCase([string]$string, [string]$keyword, [string]$delimiter){
        @($string -split $delimiter)|
             ForEach-Object{
                 if($_ -match $keyword){
                      Write-Host $_ -ForegroundColor Red -NoNewline
                 }
                 else{
                      Write-Host $_ -NoNewline
                 }
             }
    } 
    
    static[void]CaseSensitive([string]$string, [string]$keyword, [string]$delimiter){
        @($string -split $delimiter)|
             ForEach-Object{
                 if($_ -cmatch $keyword){
                      Write-Host $_ -ForegroundColor Red -NoNewline
                 }
                 else{
                      Write-Host $_ -NoNewline
                 }
                 
             }
    }        
}
```

#####出力テスト
```powershell
>> #前の例の続き
>> $replacedSample = [InsertDlm]::new($sample,"T","#")
>> [HighlightKeyword]::IgnoreCase($replacedsample.IgnoreCase,"T","#") + "`n";
>> [HighlightKeyword]::CaseSensitive($replacedsample.CaseSensitive,"T","#")

```
#####出力
<img width="250" alt="qiita_august_7.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262132/81977090-647d-1626-9fdc-76ac4517c627.png">

という感じになりました。


##リファレンス
[Regular Expressions Options](https://docs.microsoft.com/en-us/dotnet/standard/base-types/regular-expression-options?view=netframework-4.8)
[System.Text.RegularExpressions Namespace](https://docs.microsoft.com/en-us/dotnet/api/system.text.regularexpressions?view=netframework-4.8)
Lee Homes, Windows PowerShell Cookbook 3rd Edition (O'reilly)
Lee Homes, Windows PowerShellクックブック (マイクロソフト社)
山田祥寛, 独習C# 新版 (翔泳社)

##最後に
これは関数にしたほうが圧倒的にやりやすいと書きながら思いました。
近い将来、これを関数に書き換えたものを記事にしたいと思います。