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