web-dev-qa-db-ja.com

Powershellを使用してファイル名の角かっこ文字を削除する

古いAccessデータベースから移行されたSharepointサーバーに大規模なドキュメントライブラリが保存されています。これらのドキュメントのバージョン管理はユーザーによって制御され、変更が加えられたときにファイル名の末尾に追加されました。

例えば.

  1. Doc1-test(1.0).doc
  2. Doc1-test(1.1).doc
  3. Doc2-example(2.1).doc
  4. Doc2-example(2.2).doc

現在、Sharepointを使用してバージョン管理を制御しており、ファイル名に含まれているバージョンを削除する必要があります。

次のスクリプトで中程度の成功を収めました。

gi * | % { rni $_ ($_.Name -replace '(1.0)', '') }

しかし、ファイル名から角かっこを削除することはできません。したがって、私のテストディレクトリでは、ファイルは次のように変更されました

Doc1-doc(1.0).doc ----- Doc1-doc()。doc

番号の範囲は1.0から約4.5で、1200を超えるドキュメントがあるため、バージョン番号ごとに個別のスクリプトを使用する必要はありません。

3
StewartM

発生している問題は、PowerShellの_-replace_が検索に 正規表現 を使用していることです。

これは、検索クエリの角かっこ(_()_)が正規表現 キャプチャグループ として解釈されていることを意味します。

この場合、それらをリテラル文字として参照する必要があるため、角かっこをエスケープする必要があります。正規表現では、これは円記号(_\_)を使用して行われます。

したがって、-replace '\(1.0\)',''がそれを行う必要があります。

RegExを使用しているので、検索パターンとして実際のバージョン番号の代わりに "number"文字クラスまたは文字の "set" を指定することで、RegExを利用して一度に実行できます。

だから次のようなもの:

gi * | % { rni $_ ($_.Name -replace '\(1.[0-9]\)', '') }

ファイル名から_(1.<any number from 0 to 9>)_を削除します。

角かっことanythingを削除したい場合は、「任意の文字(_._)を何度でも使用できます(_*_) "正規表現パターン:

すなわち:-replace '\(.*\)',''

注:RegExは驚かされる可能性があるため(このシナリオでは、単一のファイル名の外側と内側の括弧を考えてください)、ファイルのバックアップを作成し、最初にテストを実行します。 :)

4

しかし、ファイル名から角かっこを削除することはできません。したがって、私のテストディレクトリでは、ファイルは次のように変更されました

Doc1-doc(1.0).doc ----- Doc1-doc()。doc

これは、replaceが正規表現を使用し、括弧( キャプチャグループ )をエスケープする必要があるためです。すべてのテキストをエスケープする最も簡単な方法は、 [regex] :: Escape メソッドを使用することです。

_gi * | % { rni $_ ($_.Name -replace [regex]::Escape('(1.0)'), '') }
_

括弧内のすべてを削除するだけで、Doc1-test(1.1).docDoc1-test(1.0).docなどのファイルの競合が発生することに注意してください。どちらも_Doc1-test.doc_にマップされます。

これは、拡張子なしでファイル名の最後にある括弧内のドットで区切られた数字のみに一致する正規表現を使用した私のバージョンです。希望する結果がわからないため、このコードではファイル名の競合を処理しません。

_# Get all objects in current directory that match wildcard: *(*.*).doc
Get-ChildItem -Path '.\' -Filter '*(*.*).doc' |
    # Skip folders, because XXX(1.1).doc is a valid folder name
    Where-Object {!$_.PSIsContainer} |
        # For each file
        ForEach-Object {
            # New file name = 
            # File Directory + (File name w\o extension with regex pattern (\(\d+\.\d+\))$ replaced with empty string) + File extension

            # Note, that it will create confilcts for files such as Doc1-test(1.1).doc and Doc1-test(1.0).doc,
            # both of them will end with name Doc1-test.doc
            $NewFileName = Join-Path -Path $_.DirectoryName -ChildPath (($_.BaseName -replace '(\(\d+\.\d+\))$', [string]::Empty) + $_.Extension)

            # Basic logging
            Write-Host "Renaming: $($_.FullName) -> $NewFileName"

            # Rename file.
            Rename-Item -Path $_.FullName -NewName $NewFileName
        }
_

説明 正規表現の_(\(\d+\.\d+\))$_

_1st Capturing group (\(\d+\.\d+\))

\( matches the character ( literally

\d+ match a digit [0-9]
Quantifier: + Between one and unlimited times,
as many times as possible, giving back as needed [greedy]

\. matches the character . literally

\d+ match a digit [0-9]
Quantifier: + Between one and unlimited times,
as many times as possible, giving back as needed [greedy]

\) matches the character ) literally

$ assert position at end of the string
_
2
beatcracker