删除文件与文本列表进行比较时的匹配问题

Remove matching issues when files are compared to a text list

我有一些这样的文件

Hooligans (BDrip (1080).mkv
Hocus Pocus [DIVX - ITA] - Walt Disney - HQ-.avi
Ho Cercato Il Tuo Nome h265.avi
Ho Cercato Il Tuo Nome 720.rar
Halloween 2 - Il Signore Della Morte.avi
Highlander 2 1080p.mkv
Heartbreakers - Vizio di famiglia.avi
Il cavaliere oscuro.mkv
Il cavaliere oscuro - il ritorno 1080p.mkv

在同一目录中,我有一个文本文件 (movielist.txt),它的格式总是这样:name + year.
年份始终来自 19**-20** 并且在方括号

Hooligans (1995)
Hocus Pocus (1993)
Ho cercato il tuo nome (2012)
Halloween 2 – Il signore della morte (1981)
Highlander 2 – Il ritorno (1990)
Heartbreakers – Vizio di famiglia (2001)
Il cavaliere oscuro (2008)
Il cavaliere oscuro - Il ritorno (2012)
... other text

我尝试重命名文件:

Hooligans (1995).mkv
Hocus Pocus (1993).avi
Ho cercato il tuo nome (2012).avi
Ho cercato il tuo nome (2012).rar
Halloween 2 – Il signore della morte (1981).avi
Highlander 2 – Il ritorno (1990).mkv
Heartbreakers – Vizio di famiglia (2001).avi
Il cavaliere oscuro (2008).mkv
Il cavaliere oscuro - il ritorno (2012).mkv

注意:重命名的文件数与文本文件的行数不一样。在文本文件中可以有 100 行,而要重命名的文件数可以是 50.

有两种方法,但不足以执行我要求的

第一

$movieList = Get-Content movielist.txt

# enumerate all movies
:outer foreach($file in Get-ChildItem "C:\Users\Peter\Desktop\test skript\test2" -File) {
    $bn = $file.BaseName
    # enumerate all lines of the movies to rename file
    foreach($movie in $movieList) {
        # if the Base Name is contained in the movie to rename, ie:
        # 'Young Devils (1999)' -like '*young Devils*'
        if($movie -like "*$bn*") {
            # rename the file using the movie + the file's extension, ie:
            # Young Devils (1999) + .mkv
            Rename-Item -LiteralPath $file.FullName -NewName ($movie + $file.Extension)
            # no need to keep comparing this file, if we're here
            # we can continue with next file
            continue outer
        }
    }
}

第二名:

$rootFolder = "C:\Users\Peter\Desktop\test skript\test1"
$files      = Get-ChildItem -Path $rootFolder -File
$filesNames = Get-Content -Path "$rootFolder\movielist.txt"

foreach ($name in $filesNames) 
{
    $files | Where-Object -FilterScript {
        $name -match [Regex]::Escape($_.BaseName)
    } | ForEach-Object -Process {
        $ext = $_.Extension
        Rename-Item -LiteralPath $_.FullName -NewName "$name$ext" -EA 0
    }
}

关于如何重命名示例文件的任何想法?

除了制作电影名称和年份的数组外,这里没有花哨的正则表达式

$filmTextList = @()
get-content -path $rootFolder\movielist.txt | %{$filmTextList += [PSCustomObject]@{Name=($_ -split "(\(\d{4}\))")[0];Year=($_ -split "(\(\d{4}\))")[1]}}

$filmFiles = get-childitem -path C:\Users\Peter\Desktop\test skript\test1
foreach ($film in $filmTextList){
    try{
    $matchedFilm = Get-Item ([WildcardPattern]::Escape($filmFiles.FullName -match $film.Name))
    Rename-Item -LiteralPath $matchedFilm.FullName -NewName "$($film.Name) $($film.Year)$($matchedFilm.Extension)" -ErrorAction SilentlyContinue
    }catch{}
}

否则这是您第二次尝试的工作版本:

$rootFolder = "C:\Users\Peter\Desktop\test skript\test1"
$files      = Get-ChildItem -Path $rootFolder -File
$filmTextList = @()
get-content -path $rootFolder\movielist.txt | %{$filmTextList += [PSCustomObject]@{Name=($_ -split "(\(\d{4}\))")[0];Year=($_ -split "(\(\d{4}\))")[1]}}
foreach ($film in $filmTextList) 
{
    $files | Where-Object {
        $_.BaseName -match $film.name
    } | ForEach-Object {
        $ext = $_.Extension
        Rename-Item -LiteralPath $_.FullName -NewName "$($film.name)$($film.year)$ext" -EA 0
    }
}

我冒昧地使用了你的长长的文件列表和你的 previous question 中的 'movielist.txt',因为它显示名称中有很多额外的字符,使事情变得复杂..
不仅所需名称中的 (year),而且某些文件的名称中有点而不是空格,non-ascii 连字符 (en-dashes) 等

做你想做的事你需要

  • 创建一个标题哈希表来存储 movielist.tst 文件中的实际值作为值,但也有一个 cleaned-up 版本来与
  • 进行比较
  • 用额外的 属性(我称之为 'SearchName')扩展文件数组中的每个 FileInfo object,它存储实际文件的 BaseName 的 cleaned-up 版本以进行比较反对。
$titles = Get-Content -Path 'D:\Test\movielist.txt' -Encoding UTF8 | Select-Object -Unique
# first create a Hashtable with searchable (cleaned-up) titles and the actual title you want as filename
$titleMap = @{}
foreach ($title in $titles) {
    # remove everything after a square bracket, remove the year in between brackets, 
    # remove all non-ascii characters and trim trailing spaces
    $search = ($title -replace '(\(\d{4}\)|\[.*|\s*)$' -replace '[^\x00-\x7F]+' -replace '\.|\s+', ' ').Trim()
    $titleMap[$search] = $title
}

# next, get an array of these search titels, sorted on Length reversed
# to avoid bad renames on ambiguous names like 'Il cavaliere oscuro' and 'Il cavaliere oscuro - Il ritorno'
$searchTitles = $titleMap.Keys | Sort-Object Length -Descending


# get the list of files in the foler
$files = Get-ChildItem -LiteralPath 'D:\Test' -File -Exclude 'movielist.txt'
foreach ($file in $files) {
    $search = ($file.BaseName -replace '(\(\d{4}\)|\[.*|\s*)$' -replace '[^\x00-\x7F]+' -replace '\.|\s+', ' ').Trim()
    # extend each object with a cleaned-up searchable name
    $file | Add-Member -MemberType NoteProperty -Name 'SearchName' -Value $search
}

# now loop through the search titles and try to find matching filenames from the files
foreach ($title in $searchTitles) {
    $files | Where-Object { $_.SearchName -like "*$title*" } | ForEach-Object {
        # use '-ErrorAction SilentlyContinue' to avoid errors on files that have already been renamed
        Rename-Item -LiteralPath $_.FullName -NewName ('{0}{1}' -f $titleMap[$title], $_.Extension) -ErrorAction SilentlyContinue
    }
}

  • 来自 movietext.txt 的标题说 Highlander 2 – Il ritorno (1990),但文件名只是 Highlander 2 1080p.mkv。要进行匹配,您还需要在影片文本文件中添加 Highlander 2
  • 来自 movietext.txt 的标题是 Halloween 2 – Il signore della morte (1981),但文件名是 Halloween 2 - Il Signore Della Morte.avi。同样,在文本文件中,您使用 En-Dash 而不是普通的连字符。
  • 来自 movietext.txt 的标题说 Heartbreakers – Vizio di famiglia (2001) 有一个 En-dash 而不是文件名 Heartbreakers - Vizio di famiglia.avi 的普通连字符,所以它们不匹配。

也许,因为您似乎是在像 Word 这样自动使用印刷字形而不是直接字符的文字编辑器中创建 movietext.txt,更好的解决方案是在脚本之上使用辅助函数:

function Get-ComparableName ([string]$Name) {
    $Name -replace '(\(\d{4}\)|\[.*|\s*)$' -replace                          # remove anything after (and including) a square open bracket and the year in brackets
                   '\.|\s+', ' ' -creplace                                   # replace dots into spaces and normalize spaces
                   '[\u201C\u201D\u201E\u201F\u2033\u2036]', '"' -creplace   # replace double-quote glyphs into straight quotes
                   "[\u2018\u2019\u201A\u201B\u2032\u2035]", "'" -replace    # replace single-quote glyphs into straight quotes
                   '[\p{Pd}\u2212]','-'  -replace                            # replace dash-like glyphs into a straight hyphen
                   '([^\x00-\x7F]|\p{Cf})+'                                  # remove non-ascii and invisible control characters
}

并像这样使用它:

foreach ($title in $titles) {
    $search = (Get-ComparableName $title).Trim()
    $titleMap[$search] = $title
}

再往下一点:

foreach ($file in $files) {
    $search = (Get-ComparableName $file.BaseName).Trim()
    # extend each object with a cleaned-up searchable name
    $file | Add-Member -MemberType NoteProperty -Name 'SearchName' -Value $search
}

关于文件Highlander 2 1080p.mkv,你需要在你的movielist.txt文件中添加一个标题Highlander 2 (1990),否则匹配不上..