powershell 正規表現で複数行にわたってパターンマッチさせたい(「単一行モード」)
Ride with GPSでエクスポートしたgpxファイルがGarmin etrex20(英語版)で認識できなかった。
やりたいこと
Ride with GPSでエクスポートしたgpxファイルをGarmin etrex20(英語版)で認識できるgpxファイルに加工したい。
1.問題点
Ride with GPS からエクスポートしたgpxファイルがGarmin etrexで認識されなかったので調査したところ3つの問題点があることが分かった。
- "<gpx xmlns~" の行が冗長(何かが悪い)
- "<metadata>~</metadata>"が不要
- "<name>ほげほげ</name> "の部分が日本語NG(etrex20英語版なので日本語NG。etrex20JならOKなのかな?)
1.1 Ride with GPSでエクスポートされたGPXのサンプル(UTF-8 BOM無し、改行は0x0A"\n")
<?xml version="1.0" encoding="UTF-8"?> <gpx xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"(・省略・)creator="http://ridewithgps.com/"> <metadata> <name>ほげほげ</name> <link href="https://ridewithgps.com/routes/xxxxxx"> <text>ほげほげ</text> </link> <time>2023-01-01T00:00:00Z</time> </metadata> <trk> <name>ほげほげ</name> <trkseg> <trkpt lat="37.00001" lon="140.0001"> <ele>100.1</ele> </trkpt> (・・・省略・・・) <trkpt lat="37.00002" lon="140.0002"> <ele>100.2</ele> </trkpt> </trkseg> </trk> </gpx>
1.2 etrex20で実績があるGPXファイル(UTF-8 BOM無し、改行は0x0A"\n")
<?xml version="1.0" encoding="UTF-8"?> <gpx version="1.1" xmlns="http://www.topografix.com/GPX/1/1"> <trk> <name>hogehoge</name> <trkseg> <trkpt lat="37.00001" lon="140.0001"> <ele>100.1</ele> </trkpt> (・・・省略・・・) <trkpt lat="37.00002" lon="140.0002"> <ele>100.2</ele> </trkpt> </trkseg> </trk> </gpx>
※やるべきこと
- "<gpx xmlns~" の行を、下記例に置換
- "<metadata>~</metadata>"を削除
- "<name>ほげほげ</name> "の部分を英数字に変更(手動)
2.これをpowershellでどうにかしよう
2.1.XMLとして読み込むことは諦めた
各要素を楽に扱いたいのでXMLとして読み込んでみようと考えた。よくある以下の方法だと、gpxファイルのLine7あたりでNGがあるって怒られる。
> $XML = [XML](Get-Content C:\Sample1.xml)
2.2.置換でどうにかしよう
サンプル。
# パス情報:ハードコーディング $path = "C:\temp\hogehoge.gpx" $newpath = "C:\temp\hogehoge2.gpx" # gpxファイル読込 $XML = Get-Content -Encoding UTF8 $path -raw # 古いファイルは削除 if((Test-Path -LiteralPath $newpath) -eq $true){ Remove-Item -LiteralPath $newpath } # 置換(削除) # 1.<gpx の行を置換 $XML = $XML -replace "<gpx xmlns:.*>",'<gpx version="1.1" xmlns="http://www.topografix.com/GPX/1/1">' # 2.<metadata>~</metadata> を削除(複数行にマッチさせて置換) $XML = $XML -replace '(?s)\s*<metadata>.+</metadata>','' # 出力 $XML | % { [Text.Encoding]::UTF8.GetBytes($_) } | Add-Content -LiteralPath $newpath -Encoding byte
ポイント
- Get-Content で -raw 指定で読み込むこと
- -replaceのパターン指定(正規表現)にて、「単一行モード」 を使う。'(?s)pattern' の部分。 「単一行モード」は-rawで読み込まないとだめらしい(どこかのページで見たのだが忘れた。。。orz)
- out-File -encode UTF8 はBOM付UTF8になってしまうので、「Add-Content」でByte指定で吐き出す。
※「単一行モード」:通常、ピリオド.(任意の文字)には\n(改行)は含まれない(\rは含まれるようだが)。ピリオド.でも改行とマッチさせるようなモードが単一行モードというらしい。
参考
正規表現について - PowerShell | Microsoft Learn
正規表現言語 - クイック リファレンス | Microsoft Learn
正規表現のオプション | Microsoft Learn
バージョン
PSVersion 5.1.19041.2673
powershellサンプル ファイルだけ一カ所に集めるスクリプト
ファイル整理の際に
- 複数のフォルダに分かれている(数が多い)
- フォルダが深すぎる、多分岐すぎる
みたいなことがあると、非常に面倒。
「とりあえず全部1つのフォルダにまとめちゃえ!」方式のスクリプト例。
# 適宜変更のこと。外部からCALLするようなことは考えていないので直コーディング $fromPath = "C:\xxx\fromfolder" $toPath = "C:\xxx\tofolder" $a = Get-ChildItem -LiteralPath $fromPath -Recurse -File $a | %{ # ユニークファイル名とするため、日時(ミリ秒)を取得 $prefix = Get-Date -Format yyyyMMddHHmmssfff # ファイル名先頭に上記日時文字列を付与する $newfile = (JOIN-PATH $toPath ($prefix + "_" + $_.Name)) try{ Move-Item -LiteralPath $_.FullName $newfile }catch{ Write-Output ('Error message : ' + $_.Exception.Message) } }
powerhell カギ括弧付きのファイルをファイル名変更(もしくは移動)
ファイル名に[] (カギ括弧)があると、Move-Itemがうまく動作しないことに気が付いた。
powershell ISEなどでオプションのサジェストには表示されないが「-LiteralPath」が使えるようだ。
PS > Move-Item -LiteralPath [aaa]aaa.txt ccc.txt PS > ls ディレクトリ: Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 2023/04/29 22:06 12 ccc.txt
検証
ファイルを作成
PS > echo "aho" > test.txt PS > ls Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 2023/04/29 22:06 12 test.txt
カギ括弧付きのファイル名に変更
Move-Itemはtoファイル名にカギ括弧はOKみたい。
PS > Move-Item .\test.txt [aaa]aaa.txt PS > ls Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 2023/04/29 22:06 12 [aaa]aaa.txt
カギ括弧つきファイル名を変更
空振りする。
PS > Move-Item [aaa]aaa.txt ccc.txt PS > ls Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 2023/04/29 22:06 12 [aaa]aaa.txt
ダブルクォーテーションで括ってみる。
PS > Move-Item "[aaa]aaa.txt" ccc.txt PS > ls Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 2023/04/29 22:06 12 [aaa]aaa.txt
シングルクォーテションで括ってみる。
PS > Move-Item '[aaa]aaa.txt' ccc.txt PS > ls Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 2023/04/29 22:06 12 [aaa]aaa.txt
エスケープ(\)してみる。
PS > Move-Item \[aaa\]aaa.txt ccc.txt Move-Item : コマンドレットの動的パラメーターを取得できません。指定されたワイルドカード文字パターンは無効です: [aaa 発生場所 行:1 文字:1 + Move-Item \[aaa\]aaa.txt ccc.txt + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidArgument: (:) [Move-Item]、ParameterBindingException + FullyQualifiedErrorId : GetDynamicParametersException,Microsoft.PowerShell.Commands.MoveItemCommand
エスケープ+ダブルクォーテーション。
PS > Move-Item "\[aaa\]aaa.txt" ccc.txt Move-Item : コマンドレットの動的パラメーターを取得できません。指定されたワイルドカード文字パターンは無効です: [aaa 発生場所 行:1 文字:1 + Move-Item "\[aaa\]aaa.txt" ccc.txt + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidArgument: (:) [Move-Item]、ParameterBindingException + FullyQualifiedErrorId : GetDynamicParametersException,Microsoft.PowerShell.Commands.MoveItemCommand
エスケープ+シングルクォーテーション。
PS > Move-Item '\[aaa\]aaa.txt' ccc.txt Move-Item : コマンドレットの動的パラメーターを取得できません。指定されたワイルドカード文字パターンは無効です: [aaa 発生場所 行:1 文字:1 + Move-Item '\[aaa\]aaa.txt' ccc.txt + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidArgument: (:) [Move-Item]、ParameterBindingException + FullyQualifiedErrorId : GetDynamicParametersException,Microsoft.PowerShell.Commands.MoveItemCommand
エスケープ文字がバックスラッシュかな?と思って試す。
PS > Move-Item `[aaa`]aaa.txt ccc.txt PS > ls Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 2023/04/29 22:06 12 [aaa]aaa.txt
いずれもダメでした。
Edgeでブラウザ内画面分割
ちょっと感動した記事があったのでメモ。
Edgeをブラウザ内で画面分割できる。
(例)
URL部分は、左が左の画面、右が右の画面のURLとなる。
大きなディスプレイを使っている人は、割と右側に余裕がある。 ブラウザを2つ並べてもいいのだけれど、1ブラウザで分割できれば、それはそれで利点もありそう。
・設定手順
- EdgeのURL部分に「edge://flags/#edge-split-screen」を入力してEnter
- 設定画面が表示されるので、「Microsoft Edge Split Screen」をEnabled(有効)にする
- ブラウザの再起動を促されるので、ブラウザの再起動をする
- ブラウザのアイコンメニューに分割マークが表示されるので、これを押下するとブラウザ内分割ができる
- 分割をやめる時は、再度この「分割」ボタンを押下する。(たぶん、左側だけが全表示される)
- 再度、「分割」ボタンを押下すると、履歴の中から右側に表示したいページを選択できる
- タブの追加を行ったときは、再度、ブラウザ分割をする必要あり(分割指定のスコープは当該タブのみ)
・参考
マルチタスクが楽々! デフォルトで画面分割できる有能ブラウザ2選【今日のワークハック】 | ライフハッカー・ジャパン
powershell タスクスケジューラ 「タスクの実行時に使うユーザー アカウント」の確認
とあるタスクのこの部分(タスクの実行時に使うユーザー アカウント)をpowershellで確認してみた。
・例として、タスクパス=\ の「My Backup Task」というタスクについて確認してみる。 (管理者権限のあるpowershellターミナルから実行している)
PS > ((Get-ScheduledTask -TaskPath \ | where TaskName -eq "My Backup Task" ).Principal).UserID SYSTEM
全部のタスクを列挙したければ下記の通り。(同じく管理者権限のpowershell)
Get-ScheduledTask -TaskPath \ | %{ write-output ($_.TaskName + ":" + ($_.Principal).UserID); }
コマンドラインでFirefox
ファイル名を指定して実行。
firefox https://www.yahoo.co.jp
powershellから。
> Start-Process "Firefox" -ArgumentList "-url https://www.yahoo.co.jp"
・その他のコマンドラインオプション
コマンドラインオプション - Mozilla | MDN