2

У меня есть большая библиотека документов, хранящаяся на сервере Sharepoint, который был перенесен из старой базы данных Access, управление версиями этих документов осуществлялось пользователем и добавлялось в конце имени файла при внесении изменений.

например

  1. Doc1-тест (1,0).doc
  2. Doc1-тест (1.1).doc
  3. Doc2-пример (2.1).doc
  4. Doc2-пример (2.2).doc

Сейчас мы используем Sharepoint для управления версиями, и нам нужно удалить версию, указанную в имени файла.

У меня был умеренный успех со следующим сценарием;

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

но я не могу заставить его удалить скобки из имени файла. Таким образом, в моем каталоге тестирования файлы изменились на следующие

Doc1-doc(1.0).doc ----- Doc1-doc(). Doc

Числа варьируются от 1,0 до 4,5, и существует более 1200 документов, поэтому я не против использовать индивидуальный сценарий для каждого номера версии.

2 ответа2

3

Проблема, с которой вы сталкиваетесь, заключается в том, что -replace PowerShell использует регулярные выражения для поиска.

Это означает, что скобки (()) в вашем поисковом запросе интерпретируются как группа захвата RegEx.

В этом случае вы хотите ссылаться на них как на буквальные символы, поэтому вам нужно выйти за скобки. В RegEx это делается с помощью обратной косой черты (\).

Поэтому -replace '\(1.0\)','' должен это сделать.

Поскольку вы используете RegEx, вы можете воспользоваться этим и сделать их все сразу, указав в качестве шаблона поиска класс символов "число" или "набор" символов вместо реальных номеров версий.

Так что-то вроде:

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

Удалит (1.<any number from 0 to 9>) из имен файлов.

Если вы хотите удалить квадратные скобки и все, что между ними, вы можете использовать шаблон RegEx «любой символ (.) Любое количество раз (*)»:

т.е.: -replace '\(.*\)',''

Примечание: RegEx может вас удивить (в этом случае представьте внешние и внутренние скобки в одном имени файла), поэтому сделайте резервные копии ваших файлов и сначала запустите тесты. :)

2

но я не могу заставить его удалить скобки из имени файла. Таким образом, в моем каталоге тестирования файлы изменились на следующие

Doc1-doc(1.0).doc ----- Doc1-doc(). Doc

Это потому, что replace использует регулярное выражение и скобки (группа захвата) должны быть экранированы. Самый простой способ избежать всего текста - использовать метод [regex]::Escape :

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

Обратите внимание, что простое удаление всего в скобках создаст конфликты для файлов, таких как Doc1-test(1.1).doc и Doc1-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

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .