Powershellで文字列置換

#目的
ソースコードなどのテキストファイル中の文字列置換をバッチ的におこなう（複数ファイルに対して置換を行なう場合はテキストエディタを使うより楽）。

#ソース
3組までの検索文字列・置換文字列で置換する例です（組数は容易に拡張可能だと思います）。

- 中身はほとんどPowerShellで書いてありますが、バッチファイルとして起動できます。

``` batch:replace.bat
@Powershell -NoP -C "&([ScriptBlock]::Create((gc '%~f0'|?{$_.ReadCount -gt 1}|Out-String)))" %* & exit/b
# by earthdiver1
#++++++++++++++ EDIT HERE +++++++++++++++
#$encoding = "UTF8"
$encoding = "Default" # SHIFT-JIS
$old_str1 = 'foo'
$new_str1 = 'bar'
$old_str2 = 'baz'
$new_str2 = 'qux'
$old_str3 = 'quux'
$new_str3 = 'corge'
#----------------------------------------
$tmp_str1 = '!#$%&@1'
$tmp_str2 = '!#$%&@2'
$tmp_str3 = '!#$%&@3'
foreach ($f in $Args) { gci $f -File | %{ gc $_.FullName -Encoding $encoding | %{
#++++++++++++++ EDIT HERE +++++++++++++++
#   $_ = $_ -ireplace $old_str1,$tmp_str1                  #1  case insensitive regular expression search 
#   $_ = $_ -ireplace $old_str2,$tmp_str2                  #1  case insensitive regular expression search 
#   $_ = $_ -ireplace $old_str3,$tmp_str3                  #1  case insensitive regular expression search 
#   $_ = $_ -ireplace [regex]::Escape($old_str1),$tmp_str1 #2  case insensitive simple text search
#   $_ = $_ -ireplace [regex]::Escape($old_str2),$tmp_str2 #2  case insensitive simple text search
#   $_ = $_ -ireplace [regex]::Escape($old_str3),$tmp_str3 #2  case insensitive simple text search
#   $_ = $_ -creplace $old_str1,$tmp_str1                  #3  case sensitive regular expression search 
#   $_ = $_ -creplace $old_str2,$tmp_str2                  #3  case sensitive regular expression search 
#   $_ = $_ -creplace $old_str3,$tmp_str3                  #3  case sensitive regular expression search 
    $_ = $_.Replace($old_str1,$tmp_str1)                   #4  case sensitive simple text search
    $_ = $_.Replace($old_str2,$tmp_str2)                   #4  case sensitive simple text search
    $_ = $_.Replace($old_str3,$tmp_str3)                   #4  case sensitive simple text search
#----------------------------------------
    $_ = $_.Replace($tmp_str1,$new_str1)
    $_ = $_.Replace($tmp_str2,$new_str2)
    $_ = $_.Replace($tmp_str3,$new_str3)
    $_
} | sc ($_.FullName + ".new") -Encoding $encoding }}
```

#使い方
対象のファイルをこのバッチファイルのアイコン上にドラッグ＆ドロップするか、
コマンドプロンプトで

```
$ replace  *.txt 
```

のように対象のファイル名を引数にして実行します。結果は、＜元のファイル名＞.new のファイル名で出力されます。

- 置換文字列はスクリプトの中に直書きで指定します（スクリプトの4～11行目を直接修正してください）。
- 検索文字列が重複する場合は、先に指定した文字列の組が優先されます。
- 既定の検索方法は、大小文字区別ありの単純検索です。希望する検索の種類に応じて #1～#4 の行をコメントを変更してください（#1:大小文字区別なし正規表現検索、#2:大小文字区別なし単純検索、#3:大小文字区別あり正規表現検索、4#:大小文字区別あり単純検索）。
- フォルダ名を指定すると、そのフォルダ直下の全ファイルを対象とします。サブフォルダ内のファイルは対象外となります[^1]。

[^1]: サブフォルダ以下のファイルも対象とするには　gci （Get-ChildItem コマンドレット）のオプションに -Recurse を追加します。

#注意
例えば1組目の置換文字列が2番目の組の検索文字列にマッチしてもこれを置換してしまわないように、一旦、無意味かつ複雑な中間文字列に置換しています。その関係で、正規表現による検索・置換を行なう場合、置換文字列に$1などでキャプチャした文字列を指定しても正常に動作しません。どうしてもキャプチャした文字列を置換文字列に指定したい場合には

```
    $_ = $_ -ireplace $old_str1,$new_str1                  #1  case insensitive regular expression search 
```

のように修正してください（後続の組の置換に気をつけてください）。

#おまけ
入力が BOM なし UTF8 エンコーディング（UTF-8N）の場合に上記のコードで \$encoding に UTF8 をセットすると、出力が BOM 付きに変わってしまいます。以下は、UTF-8N の BOM なしを維持する例です。検索文字列・置換文字列の組は１つとしました（１組なので中間文字列への一時的な置換は不要）。

``` powershell:replace-utf8n.bat
@Powershell -NoP -C "&([ScriptBlock]::Create((gc '%~f0'|?{$_.ReadCount -gt 1}|Out-String)))" %* & exit/b
# by earthdiver1
#++++++++++++++ EDIT HERE +++++++++++++++
$old_str = 'foo'
$new_str = 'bar'
#----------------------------------------
foreach($f in $Args) { gci $f -File | %{ gc $_.FullName -Encoding UTF8 | %{
#++++++++++++++ EDIT HERE +++++++++++++++
#   $_ = $_ -ireplace $old_str,$new_str                  #1  case insensitive regular expression search 
#   $_ = $_ -ireplace [regex]::Escape($old_str),$new_str #2  case insensitive simple text search
#   $_ = $_ -creplace $old_str,$new_str                  #3  case sensitive regular expression search 
    $_ = $_.replace($old_str,$new_str)                   #4  case sensitive simple text search
#----------------------------------------
    [Text.Encoding]::UTF8.GetBytes($_)
} | sc ($_.FullName + ".new") -Encoding Byte }}
```
　

クリエイティブ・コモンズ 表示 - 継承 4.0 国際