日本語検索で情報の検索のし辛いPowershellのコーディングをChatGPTに助けてもらった記録

# 事のあらまし
以下の記事で対応した横持ちデータの対応。前提に合致しないデータが存在して、よわよわエンジニアの私は検索の海をさまよっていたわけだが、、、

https://qiita.com/carbonss/items/ad8916121053cd2435be

## 総括
* マジで先生に聞いているような自然言語でほしい書き方がわかる。
* 検索で取っ掛かりができたら色んなサイトを巡るよりChatGPTで精度上げたほうがいい。
    * 自然言語で質問できるので、『え、それどういうこと？』とか、『じゃあ、これならどう？』みたいな質問で適切な回答が帰ってくる。すごい。
* よわよわエンジニア（社内SE）ほど恩恵がある。

## やりたかったこと
タブ区切りで以下のように入っているデータを
```
UNIQUE memo
"1"    "ABCD,""EF,GH"",IJK"
```
Import-CSVでデータにしたが、`$memo`の`""EF,GH""`の間のカンマを取り除きたい！となったのだが、
どうやればいいのか検討もつかない・・・、が正規表現で該当の文字列を特定することができるところまでは来た

## ChatGPTとのやり取り

まずストレートに聞いてみた

### Q:powershellでStringをSplitするときに、特定の記号に囲まれている場合はデリミタの判定外にする記述をしたいです。どうすればよいでしょうか？
PowerShell で文字列を split して特定の記号に囲まれた文字列を分割したい場合、-Split 演算子を使って以下のように記述することができます。

```powershell
$string = "foo;bar;;baz"
$split = [char[]](';')
$parts = $string -split $split, ($string -replace '\w+', '').Length + 1
Write-Output $parts
```
上記の例では、分割デリミタに ';' を指定しています。特定の記号に囲まれている文字列を分割したい場合は、-replace コマンドレットを使って特定の記号を特定の文字列に置換し、置換後の文字列で split を実行することができます。

```powershell
$string = "foo[bar];baz"
$split = [char[]](';')
$parts = $string -replace '\[\w+\]', '_' -split $split
Write-Output $parts
```
上記の例では、'[bar]' のように記号で囲まれた文字列を '_' に置換して分割しています。

#### 気づき
* 元の文字列から該当の箇所をまるっと取り出してReplaceした内容で置換をすればええな！！
* でも書き方はわからない

### Q:powershellで文字列から正規表現に合致した内容を複数列挙する方法を教えてください
PowerShell で複数のマッチする文字列を列挙するには、Select-String コマンドレットか [regex] クラスを使います。

Select-String コマンドレットの場合、以下のように記述することで列挙することができます。

```powershell
$string = "The IP addresses are 192.168.0.1 and 192.168.0.2."
$pattern = "\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b"
$matches = Select-String -InputObject $string -Pattern $pattern -AllMatches
$ipAddresses = $matches.Matches.Value
Write-Output $ipAddresses
```
上記の例では、Select-String コマンドレットによって複数のマッチする文字列を検索し、$matches 変数に格納しています。次に、$matches 変数から各マッチする文字列を列挙するために $matches.Matches.Value プロパティを使っています。

[regex] クラスの場合、以下のように記述することで列挙することができます。

```powershell
$string = "The IP addresses are 192.168.0.1 and 192.168.0.2."
$pattern = "\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b"
$regex = [regex]::new($pattern)
$matches = $regex.Matches($string)
$ipAddresses = foreach ($match in $matches) { $match.Value }
Write-Output $ipAddresses
```
上記の例では、.NET Framework の System.Text.RegularExpressions ネームスペースに含まれる [regex] クラスを使って文字列から正規表現に合致する文字列を抽出しています。抽出した各文字列を変数 $ipAddresses に列挙するために、foreach ステートメントを使っています。

#### 気づき
* こいつめちゃくちゃ賢いな。
* 複数マッチしただけでいいからそれ聞いてみよう

### 複数マッチした場合のみ条件分岐してIPFoundと表示し、そうでない場合は何も出力しないコードを教えてください。
複数マッチした場合にのみ条件分岐して「IPFound」と表示し、そうでない場合は何も出力しないようなコードは以下のように記述することができます。

```powershell
$string = "The IP addresses are 192.168.0.1 and 192.168.0.2."
$pattern = "\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b"
$regex = [regex]::new($pattern)
$matches = $regex.Matches($string)
if ($matches.Count -gt 1) {
    Write-Output "IPFound"
}
```
上記の例では、正規表現に合致する文字列の数を求めるために、.NET Framework の System.Text.RegularExpressions ネームスペースに含まれる [regex] クラスを使っています。マッチした文字列の数を $matches.Count プロパティで取得し、2 以上ある場合（複数マッチした場合）にのみ「IPFound」と表示するような条件分岐を行っています。

#### 気づき
* その出力の所、IPの置き換えにすれば完成じゃん

### Powershellで$stringからIPアドレスを正規表現で取り出し、1つ以上合致した場合にその該当箇所のIPアドレスをForEach文でループしてIPアドレスの部分をIP1,IP2,IP3...と置き換え、置き換え後の文字列を出力する処理を行うように書き直してください。

次のようなコードで$stringからIPアドレスを正規表現で取り出し、1つ以上合致した場合にその該当箇所のIPアドレスをForEach文でループしてIPアドレスの部分をIP1,IP2,IP3...と置き換え、置き換え後の文字列を出力する処理を行うことができます。

```powershell
$string = "The IP addresses are 192.168.0.1 and 192.168.0.2."
$pattern = "\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b"
$regex = [regex]::new($pattern)
$matches = $regex.Matches($string)
if ($matches.Count -gt 0) {
    $counter = 0
    $newString = $string
    foreach ($match in $matches) {
        $counter++
        $newString = $newString.Replace($match.Value, "IP$counter")
    }
    Write-Output $newString
}
```
上記の例では、正規表現に合致する文字列を [regex] クラスを使って取得します。合致する文字列が 1 つ以上ある場合、ForEach 文を使ってマッチした各文字列を順に取り出します。取り出した文字列を IP1, IP2, IP3 ... といった形式で置き換えます。最後に置き換え後の文字列を出力します。

#### 気づき
* ChatGPTやば。
### ありがとう。完成しました。
ご質問ありがとうございました。何かさらに質問がありましたら、どうぞお気軽にお尋ねください。