Powershellでcsvデータからgrep的ななにか
概説
CSVをデータベースにして検索システムを作った際にUnix系のgrep
のように検索語に強調をつけたかった。
注意点
職場のがお粗末だったのでもっといい方法はないかと模索したPowerShell初心者の備忘録です。あんまりPowerShellでの開発経験がなかったため備忘録もかねてかなり冗長に説明しています。適宜読み飛ばしてもらったほうがいいかもしれません。
実行環境
- Windows 10
- PowerShell
環境面の挫折ポイント
- どうやらWindows PowerShellではANSIIエスケープが使えるらしい(参考URL参照)
- 職場の環境が対応していなかったため断念
-
Write-Host
の-Foreground-Color
オプションで無理やり対応させた
元データ
phsdata.csv
PS > $phs | ft
氏名 所属 PHS番号
-- -- -----
白鵬 内科 5678
鶴竜 内科 4839
正代 会計課 1823
朝乃山 外科 4852
貴景勝 放射線科 1800
照ノ富士 精神科 8493
隆の勝 内科 2939
高安 内科 3884
御獄海 外科 2858
大栄翔 精神科 1923
前処理
Where-Objectについて
- どうやらWindows PowerShellではANSIIエスケープが使えるらしい(参考URL参照)
- 職場の環境が対応していなかったため断念
-
Write-Host
の-Foreground-Color
オプションで無理やり対応させた
元データ
phsdata.csv
PS > $phs | ft
氏名 所属 PHS番号
-- -- -----
白鵬 内科 5678
鶴竜 内科 4839
正代 会計課 1823
朝乃山 外科 4852
貴景勝 放射線科 1800
照ノ富士 精神科 8493
隆の勝 内科 2939
高安 内科 3884
御獄海 外科 2858
大栄翔 精神科 1923
前処理
Where-Objectについて
PS > $phs | ft
氏名 所属 PHS番号
-- -- -----
白鵬 内科 5678
鶴竜 内科 4839
正代 会計課 1823
朝乃山 外科 4852
貴景勝 放射線科 1800
照ノ富士 精神科 8493
隆の勝 内科 2939
高安 内科 3884
御獄海 外科 2858
大栄翔 精神科 1923
Where-Objectについて
PowerShellには便利なWhere-Object
というフィルタ関数があります。
PS > $phs | Where-Object {$_.所属 -match '内'} | ft
氏名 所属 PHS番号
-- -- -----
白鵬 内科 5678
鶴竜 内科 4839
隆の勝 内科 2939
高安 内科 3884
この例だと所属に対して「内」でフィルタをかけています。もちろんデータ型はSystem.Array
型です。
(実際はSystem.Array
にネストされたPSCustomObject
型の集合)
PS > $match = $phs | Where-Object {$_.所属 -match '内'}
PS> $match.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
PS > $match | ForEach-Object -Process { $_.GetType()}
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False PSCustomObject System.Object
True False PSCustomObject System.Object
True False PSCustomObject System.Object
True False PSCustomObject System.Object
特に標準でハイライトにしてくれる機能は用意されていないようです。
標準出力に出力してくれるWrite-Host
にも特定文字列に対して文字色を変化させるようなオプションは用意されていません。
ここから検索語に対してハイライト化する処理を無理やり追加したいとおもいます。
Out-String
PowerShellには出力を文字列にしてくれるOut-String
という便利な関数があるそうです。
使わない手はないですね。
PS > $result = $phs | Where-Object {$_.所属 -match '内'} | Out-String
PS > $result
氏名 所属 PHS番号
-- -- -----
白鵬 内科 5678
鶴竜 内科 4839
隆の勝 内科 2939
高安 内科 3884
見た目は変わりませんが、ちゃんと文字列型になっているはずです。
あくまでも文字列ですのでFormat-Table
などは有効ではありません。もしそのような処理をしたい場合は文字列化以前に行うべきです。
PS > $result.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String System.Object
-split演算子
PowerShellには-split
演算子という形で文字列の分割メソッドが提供されているようです。さっきの検索文字列で区切ってみたいと思います。
PS > $result = $result -split '内'
PS > $result
氏名 所属 PHS番号
-- -- -----
白鵬
科 5678
鶴竜
科 4839
隆の勝
科 2939
高安
科 3884
検索文字列を除いた文字列が配列に格納にされている状態です。
もちろん型はSystem.Array
型に変化しています。
PS > $result.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String[] System.Array
本題
ここで配列となった文字列に対してWrite-Host
を用いて装飾を加えていきたいと思います。
繰り返し処理に関してはForeach-Object
を用いてパイプでつなぎました。
Write-Host
の-NoNewline
は最後の改行をキャンセルする仕様です。
PS > $result | ForEach-Object -Process {
Write-Host $_ -NoNewline
Write-Host '内' -NoNewline -ForegroundColor Yellow
}
氏名 所属 PHS番号
-- -- -----
白鵬 内科 5678
鶴竜 内科 4839
隆の勝 内科 2939
高安 内科 3884
内
一連の処理を関数化
実例
test.ps1
$phs = Import-Csv .\phsdata.txt
function Search-Data-By-Value($value,$column,$data){
$result = $data | Where-Object {$_.$column -match $value} | Out-String
$result -split $value | ForEach-Object -Process {
Write-Host $_ -NoNewline
Write-Host $value -NoNewline -ForegroundColor Yellow
} -End {
Write-Host 'を検索しました。'
}
}
Search-Data-By-Value '内' '所属' $phs
$phs = Import-Csv .\phsdata.txt
function Search-Data-By-Value($value,$column,$data){
$result = $data | Where-Object {$_.$column -match $value} | Out-String
$result -split $value | ForEach-Object -Process {
Write-Host $_ -NoNewline
Write-Host $value -NoNewline -ForegroundColor Yellow
} -End {
Write-Host 'を検索しました。'
}
}
Search-Data-By-Value '内' '所属' $phs
備考
-
Foreach-Object
の-End
を用いて無理やり最後の「内」をそれっぽく見せました。 -
PSCustomObject
のカラム指定は変数でも可能なのでカラム指定は引数にしました。
考察
- PowerShellは標準で
Import-Csv
のようなパーサを用意してくれているのでちょっとしたデータベースlikeな処理には向いてるかも。
- 今回は
Write-Host
に収束したが、Write-Output
等を活用していろんなことができそう。
- 最後の余計な検索語の表示に関しては消去する方法が思いつかなかった。誰か頭のいいひと教えてください。
参考URL
Import-Csv
のようなパーサを用意してくれているのでちょっとしたデータベースlikeな処理には向いてるかも。Write-Host
に収束したが、Write-Output
等を活用していろんなことができそう。https://forsenergy.com/ja-jp/windowspowershellhelp/html/d704165a-2007-4c7c-bab9-6e2d2c8c5ca5.htm
https://docs.microsoft.com/ja-jp/powershell/module/microsoft.powershell.core/about/about_special_characters?view=powershell-7.1
Author And Source
この問題について(Powershellでcsvデータからgrep的ななにか), 我々は、より多くの情報をここで見つけました https://qiita.com/croquisdukke/items/fdfaf37c4db8c64d3cea著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .