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