Как удалить недопустимые символы перед попыткой сохранить имена файлов?

Мне удалось найти способ использования метода GetInvalidFileNameChars() в PowerShell script. Однако, похоже, он также отфильтровывает пробелы (чего я не хочу).

EDIT: Возможно, я не прошу об этом достаточно ясно. Я хочу, чтобы функция ниже включала пробелы, которые уже существуют в именах файлов. В настоящее время script отфильтровывает пробелы.

Function Remove-InvalidFileNameChars {

param([Parameter(Mandatory=$true,
    Position=0,
    ValueFromPipeline=$true,
    ValueFromPipelineByPropertyName=$true)]
    [String]$Name
)

return [RegEx]::Replace($Name, "[{0}]" -f ([RegEx]::Escape([String][System.IO.Path]::GetInvalidFileNameChars())), '')}

Ответ 1

Приведение символьного массива в System.String фактически похоже на элементы массива с пробелами, что означает, что

[string][System.IO.Path]::GetInvalidFileNameChars()

делает то же самое, что и

[System.IO.Path]::GetInvalidFileNameChars() -join ' '

когда вы действительно хотите

[System.IO.Path]::GetInvalidFileNameChars() -join ''

Как @mjolinor упоминается (+1), это вызвано разделителем выходных полей ($OFS).

Доказательства:

PS C:\> [RegEx]::Escape([string][IO.Path]::GetInvalidFileNameChars())
"\ \ \|\  \ ☺\ ☻\ ♥\ ♦\ ♣\ ♠\ \\ \t\ \n\ ♂\ \f\ \r\ ♫\ ☼\ ►\ ◄\ ↕\ ‼\ ¶\ §\ ▬\ ↨\ ↑\ ↓\ →\ ←\ ∟\ ↔\ ▲\ ▼\ :\ \*\ \?\ \\\ /
PS C:\> [RegEx]::Escape(([IO.Path]::GetInvalidFileNameChars() -join ' '))
"\ \ \|\  \ ☺\ ☻\ ♥\ ♦\ ♣\ ♠\ \\ \t\ \n\ ♂\ \f\ \r\ ♫\ ☼\ ►\ ◄\ ↕\ ‼\ ¶\ §\ ▬\ ↨\ ↑\ ↓\ →\ ←\ ∟\ ↔\ ▲\ ▼\ :\ \*\ \?\ \\\ /
PS C:\> [RegEx]::Escape(([IO.Path]::GetInvalidFileNameChars() -join ''))
"\| ☺☻♥♦\t\n♂\f\r♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼:\*\?\\/
PS C:\> $OFS=''
PS C:\> [RegEx]::Escape([string][IO.Path]::GetInvalidFileNameChars())
"\| ☺☻♥♦\t\n♂\f\r♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼:\*\?\\/

Измените свою функцию примерно так:

Function Remove-InvalidFileNameChars {
  param(
    [Parameter(Mandatory=$true,
      Position=0,
      ValueFromPipeline=$true,
      ValueFromPipelineByPropertyName=$true)]
    [String]$Name
  )

  $invalidChars = [IO.Path]::GetInvalidFileNameChars() -join ''
  $re = "[{0}]" -f [RegEx]::Escape($invalidChars)
  return ($Name -replace $re)
}

и он должен делать то, что вы хотите.

Ответ 2

Я подозреваю, что это связано с тем, что символы, не отображаемые, принуждаются к [string] для операции регулярного выражения (и заканчиваются выражением как пробелы).

Посмотрите, не работает ли это лучше:

([char[]]$name | where { [IO.Path]::GetinvalidFileNameChars() -notcontains $_ }) -join ''

Это сделает прямое сравнение char и, кажется, более надежным (встроенные пространства не удаляются).

$name = 'abc*\ def.txt'
([char[]]$name | where { [IO.Path]::GetinvalidFileNameChars() -notcontains $_ }) -join ''

abc def.txt

Изменить - я считаю, что @Ansgar правильно относится к пространству, вызванному литьем массива символов в строку. Пространство вводится через $OFS.

Ответ 3

Мне нужны пробелы для замены всех недопустимых символов, поэтому пространство заменяется пробелом

$Filename = $ADUser.SamAccountName
[IO.Path]::GetinvalidFileNameChars() | ForEach-Object {$Filename = $Filename.Replace($_," ")}
$Filename = "folder\" + $Filename.trim() + ".txt"

Ответ 4

[System.IO.Path]::GetInvalidFileNameChars() возвращает массив недопустимых символов. Если он возвращает символ пробела для вас (что он не делает для меня), вы всегда можете перебирать массив и удалять его.

> $chars = @()
> foreach ($c in [System.IO.Path]::GetInvalidFileNameChars())
  {
     if ($c -ne ' ')
     {
        $chars += $c
     }
  }

Затем вы можете использовать $chars, поскольку вы использовали бы выход из GetInvalidFileNameChars().

Ответ 5

Попробуйте этот однострочный вкладыш с той же базовой функцией.

для соответствия

'?Some "" File Name <:.txt' -match ("[{0}]"-f (([System.IO.Path]::GetInvalidFileNameChars()|%{[regex]::Escape($_)}) -join '|'))