亀の甲羅2

今日もまた朝とく起きて励まなん窓に明るきありあけの月

powershell 正規表現で複数行にわたってパターンマッチさせたい(「単一行モード」)

Ride with GPSでエクスポートしたgpxファイルがGarmin etrex20(英語版)で認識できなかった。

やりたいこと

Ride with GPSでエクスポートしたgpxファイルをGarmin etrex20(英語版)で認識できるgpxファイルに加工したい。

1.問題点

Ride with GPS からエクスポートしたgpxファイルがGarmin etrexで認識されなかったので調査したところ3つの問題点があることが分かった。

  1. "<gpx xmlns~" の行が冗長(何かが悪い)
  2. "<metadata>~</metadata>"が不要
  3. "<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>

※やるべきこと

  1. "<gpx xmlns~" の行を、下記例に置換
  2. "<metadata>~</metadata>"を削除
  3. "<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