Vinnaren i pepparkakshustävlingen!
2023-12-12, 04:00
  #1
Medlem
Söker bred hjälp med att komma vidare i ett batch-skript (eller liknande automation) som ska söka igenom mappar, efter filer med ”otillåtna” tecken filnamnet, och omedelbart ersätta såna förbjudna otillåtna tecknen med förinställda alternativ. För god OS-kompatibilitet har jag börjat i MS Powershell (sitter på Win10 själv).
Jag vet det finns ExIF och andra verktyg man kan använda sig av, men jag vill göra det oberoende av tredjepartsgrejor.

Jag tyckte ska ska väl bara vara att iterera igenom filerna och deras namn, och ersätta alla förekomster av angivna tecken med andra förutbestämda tecken. Men icke. Problemet är att jag stöter hela tiden på stora hinder med att dom ”otillåtna” tecknen måste anges i koden och accepteras då inte som giltig kod, alternativt kräver invecklade bearbetningar för att få PS att tolka dom som sträng-innehåll. Blir ett himla micklande med escape-scenarion som jag inte lyckas komma runt på ett konstruktivt sätt.

T.ex. om man vill ange att det är citat-tecken (”) som man vill hitta- och ersätta i filnamn, då ska citat-tecken skrivas in i koden omgärdade av … citat-tecken som avgränsar strängdatan i PS. Då blir koden
Kod:
 if ($_.Value -match """)
.. vilket PS inte godkänner som giltig kod.
Escape-tecknet i PS funkar i fallet med citat-tecken,
Kod:
if ($_.Value -match "`"")
men den lösningen funkar inte för tecken som + eller * eller Ù och andra tecken, vilket förmodligen kräver helt andra lösningar – okända för mig just nu. (se kod-försök nedan)

Jag är osäker på om det är kunskapsnivån eller lösningen det är fel på, eller om PS är dåligt rustat för såna här operationer? Har snöat in lite djupt i hjärnan på det här nu. Söker lite hjälp med det här.
Jag har 152 ASCII-tecken jag vill kunna hitta och ersätta i filnamn, och efter några dagar har jag bara lyckats få en process som hittar och ersätter 8 stycken. Här är vad jag gjort hittills, försöker fixa så asterisk och plus funkar. Får inte till ens det.
Kod:
$Folder = "c:\testmapp\undermapp"
$Items = Get-ChildItem -Path $Folder -Recurse
	 
$UnsupportedChars = "[!#$%&'()*+,-./:;<=>?@[\]^_`{|}~€‚ƒ`„…†‡ˆ‰Š‹ŒŽ‘’`“`”•–—˜™š›œžŸ¡¢£¤¥¦§¨©ª«¬®¯ÅÅÖ]"
	 
foreach ($item in $items){
  filter Matches($UnsupportedChars){
    $item.Name | Select-String -AllMatches $UnsupportedChars |
    Select-Object -ExpandProperty Matches
    Select-Object -ExpandProperty Values
  }

  $newFileName = $item.Name
  Matches $UnsupportedChars | ForEach-Object {
    Write-Host "Otillatet tecken i $($item.FullName): $($_.Value)" -ForegroundColor Red
	        
    if ($_.Value -match "!") { $newFileName = ($newFileName -replace "!", "") }
    if ($_.Value -match "`"") { $newFileName = ($newFileName -replace "`"", "") }
    if ($_.Value -match "#") { $newFileName = ($newFileName -replace "#", "") }
    if ($_.Value -match "$") { $newFileName = ($newFileName -replace "$", "") }
    if ($_.Value -match "%") { $newFileName = ($newFileName -replace "%", "") }
    if ($_.Value -match "&") { $newFileName = ($newFileName -replace "&", " and ") }
    if ($_.Value -match "'") { $newFileName = ($newFileName -replace "'", "") } 
    # if ($_.Value -match ""*"") { $newFileName = ($newFileName -replace "*", "") }
    # if ($_.Value -match "+") { $newFileName = ($newFileName -replace ''+'', "") }
    # osv osv
   }

  if (($newFileName -ne $item.Name)){
    Rename-Item $item.FullName -NewName ($newFileName)
    Write-Host "$($item.Name) andrat till $newFileName" -ForegroundColor Green
    } 
}
Och här en lista på tecknen jag vill hitta och ersätta i filnamn:
Och här är tecknen jag vill hitta i filnamn, om dom finns, och ersätta:
Kod:
!#$%&'()*+,-./:;<=>?@[\]^_`{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâã  äåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ
Krånglar jag till det? Är PS ett dåligt val? Är det möjligt att ta sig igenom allt detta med olika escape-lösningar eller liknande?
Hur skulle ni göra för den här funktionaliteten?
Även helt andra förslag välkomna, men helst så OS-oberoende som möjligt utan tredjepart-beroenden.
__________________
Senast redigerad av Marinerad65 2023-12-12 kl. 04:14.
Citera
2023-12-12, 04:57
  #2
Medlem
Kan du inte jämföra varje character med deras ascii värde istället för att försöka escapa strängarna?
__________________
Senast redigerad av hassanlol 2023-12-12 kl. 05:11.
Citera
2023-12-12, 06:41
  #3
Medlem
Citat:
Ursprungligen postat av hassanlol
Kan du inte jämföra varje character med deras ascii värde istället för att försöka escapa strängarna?
Du har så rätt! Shit. Powershell använder ANSI som standard, så om man inte anger "+" som illegalt tecken, utan istället "[char]43" (ascii för plus), så kommer man troligtvis förbi mycket av tecken-krånglet.

Insåg just att med koden ovan så måste jag då kunna ange alla "[char]x" ASCII-nummer på rad i variabeln $UnsupportedChars. Typ [char]43 [char]44 [char]45 [char]46 [char]47 ... på något sätt, och samtidigt bibehålla att varje tecken individuellt ska utgöra ett förbjudet tecken, inte alla tecken på rad efter varandra. Kanske måste göra en Array istället?

Och ser även att med koden jag har nu, så kommer skriptet bara byta ut 1 förbjudet tecken per filnamn. Så om det är flera förbjudna tecken i samma filnamn ... då måste man köra flera gånger .. hm, måste försöka fixa så att skriptet kan ändra alla förbjudna tecken i varje filnamn i ett svep .. på nåt sätt ...
Citera
2023-12-12, 08:16
  #4
Medlem
Enterprises avatar
Citat:
Ursprungligen postat av Marinerad65
Söker bred hjälp med att komma vidare i ett batch-skript (eller liknande automation) som ska söka igenom mappar, efter filer med ”otillåtna” tecken filnamnet, och omedelbart ersätta såna förbjudna otillåtna tecknen med förinställda alternativ. För god OS-kompatibilitet har jag börjat i MS Powershell (sitter på Win10 själv).
Jag vet det finns ExIF och andra verktyg man kan använda sig av, men jag vill göra det oberoende av tredjepartsgrejor.

Jag tyckte ska ska väl bara vara att iterera igenom filerna och deras namn, och ersätta alla förekomster av angivna tecken med andra förutbestämda tecken. Men icke. Problemet är att jag stöter hela tiden på stora hinder med att dom ”otillåtna” tecknen måste anges i koden och accepteras då inte som giltig kod, alternativt kräver invecklade bearbetningar för att få PS att tolka dom som sträng-innehåll. Blir ett himla micklande med escape-scenarion som jag inte lyckas komma runt på ett konstruktivt sätt.

T.ex. om man vill ange att det är citat-tecken (”) som man vill hitta- och ersätta i filnamn, då ska citat-tecken skrivas in i koden omgärdade av … citat-tecken som avgränsar strängdatan i PS. Då blir koden
Kod:
 if ($_.Value -match """)
.. vilket PS inte godkänner som giltig kod.
Escape-tecknet i PS funkar i fallet med citat-tecken,
Kod:
if ($_.Value -match "`"")
men den lösningen funkar inte för tecken som + eller * eller Ù och andra tecken, vilket förmodligen kräver helt andra lösningar – okända för mig just nu. (se kod-försök nedan)

Jag är osäker på om det är kunskapsnivån eller lösningen det är fel på, eller om PS är dåligt rustat för såna här operationer? Har snöat in lite djupt i hjärnan på det här nu. Söker lite hjälp med det här.
Jag har 152 ASCII-tecken jag vill kunna hitta och ersätta i filnamn, och efter några dagar har jag bara lyckats få en process som hittar och ersätter 8 stycken. Här är vad jag gjort hittills, försöker fixa så asterisk och plus funkar. Får inte till ens det.
Kod:
$Folder = "c:\testmapp\undermapp"
$Items = Get-ChildItem -Path $Folder -Recurse
	 
$UnsupportedChars = "[!#$%&'()*+,-./:;<=>?@[\]^_`{|}~€‚ƒ`„…†‡ˆ‰Š‹ŒŽ‘’`“`”•–—˜™š›œžŸ¡¢£¤¥¦§¨©ª«¬®¯ÅÅÖ]"
	 
foreach ($item in $items){
  filter Matches($UnsupportedChars){
    $item.Name | Select-String -AllMatches $UnsupportedChars |
    Select-Object -ExpandProperty Matches
    Select-Object -ExpandProperty Values
  }

  $newFileName = $item.Name
  Matches $UnsupportedChars | ForEach-Object {
    Write-Host "Otillatet tecken i $($item.FullName): $($_.Value)" -ForegroundColor Red
	        
    if ($_.Value -match "!") { $newFileName = ($newFileName -replace "!", "") }
    if ($_.Value -match "`"") { $newFileName = ($newFileName -replace "`"", "") }
    if ($_.Value -match "#") { $newFileName = ($newFileName -replace "#", "") }
    if ($_.Value -match "$") { $newFileName = ($newFileName -replace "$", "") }
    if ($_.Value -match "%") { $newFileName = ($newFileName -replace "%", "") }
    if ($_.Value -match "&") { $newFileName = ($newFileName -replace "&", " and ") }
    if ($_.Value -match "'") { $newFileName = ($newFileName -replace "'", "") } 
    # if ($_.Value -match ""*"") { $newFileName = ($newFileName -replace "*", "") }
    # if ($_.Value -match "+") { $newFileName = ($newFileName -replace ''+'', "") }
    # osv osv
   }

  if (($newFileName -ne $item.Name)){
    Rename-Item $item.FullName -NewName ($newFileName)
    Write-Host "$($item.Name) andrat till $newFileName" -ForegroundColor Green
    } 
}
Och här en lista på tecknen jag vill hitta och ersätta i filnamn:
Och här är tecknen jag vill hitta i filnamn, om dom finns, och ersätta:
Kod:
!#$%&'()*+,-./:;<=>?@[\]^_`{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâã  äåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ
Krånglar jag till det? Är PS ett dåligt val? Är det möjligt att ta sig igenom allt detta med olika escape-lösningar eller liknande?
Hur skulle ni göra för den här funktionaliteten?
Även helt andra förslag välkomna, men helst så OS-oberoende som möjligt utan tredjepart-beroenden.
En fråga. Är det inte lite "risky" att ersätta otillåtna tecken med "", alltså att ta bort dom?
Tänker att detta kan skapa risk för konflikt om samma filnamn i samma path. Är det inte bättre att ersätta ett otillåtet tecken med t.ex. två eller tre tillåtna.

Sen förstår jag inte riktigt att Powershell skulle vara så O/S-vänligt. I min värld är Python i så fall enklare att köra på alla plattformar.

För att undvika total spaghettikod är en smartare lösning att skapa en array/lista med otillåtna tecken och en motsvarande array/lista med ersättningar. Då letar koden efter otillåtna tecken i den första listan och när den hittar det så tar den rätt ersättningstecken från den andra listan.
__________________
Senast redigerad av Enterprise 2023-12-12 kl. 08:19.
Citera
2023-12-12, 08:20
  #5
Medlem
SchrodingersPizzas avatar
Jag hade använt regex istället, samt utgått från tecken jag vill spara istället för tecken jag vill ta bort.

Typ så här:
Kod:
$Folder = "c:\testmapp\undermapp"
$Items = Get-ChildItem -Path $Folder -Recurse

$AllowedCharsPattern = "[^a-zA-Z0-9 ._-]"

foreach ($item in $items) {
    $newFileName = $item.Name -replace $AllowedCharsPattern, ''

    if ($newFileName -ne $item.Name) {
        Rename-Item $item.FullName -NewName $newFileName
        Write-Host "$($item.Name) changed to $newFileName" -ForegroundColor Green
    }
}
Citera
2023-12-12, 09:22
  #6
Medlem
Enterprises avatar
Citat:
Ursprungligen postat av SchrodingersPizza
Jag hade använt regex istället, samt utgått från tecken jag vill spara istället för tecken jag vill ta bort.

Typ så här:
Kod:
$Folder = "c:\testmapp\undermapp"
$Items = Get-ChildItem -Path $Folder -Recurse

$AllowedCharsPattern = "[^a-zA-Z0-9 ._-]"

foreach ($item in $items) {
    $newFileName = $item.Name -replace $AllowedCharsPattern, ''

    if ($newFileName -ne $item.Name) {
        Rename-Item $item.FullName -NewName $newFileName
        Write-Host "$($item.Name) changed to $newFileName" -ForegroundColor Green
    }
}
Det är ju perfekt att använda Regex som bokstavligen är gjort för att hitta och ersätta tecken.
Ett litet förslag till modifering (ej testkört) för att undvika risk för namnkrock:

Kod:
$Folder = "c:\testmapp\undermapp"
$Items = Get-ChildItem -Path $Folder -Recurse

$AllowedCharsPattern = "[^a-zA-Z0-9 ._-]"

foreach ($item in $items) {
    $newFileName = $item.Name -replace $AllowedCharsPattern, ''
    $baseFileName = [System.IO.Path]::GetFileNameWithoutExtension($newFileName)
    $extension = [System.IO.Path]::GetExtension($newFileName)
    $counter = 0

    while (Test-Path (Join-Path $item.DirectoryName $newFileName)) {
        $newFileName = "${baseFileName}_${counter}${extension}"
        $counter++
    }

    if ($newFileName -ne $item.Name) {
        Rename-Item $item.FullName -NewName $newFileName
        Write-Host "$($item.Name) changed to $newFileName" -ForegroundColor Green
    }
}
Citera

Stöd Flashback

Flashback finansieras genom donationer från våra medlemmar och besökare. Det är med hjälp av dig vi kan fortsätta erbjuda en fri samhällsdebatt. Tack för ditt stöd!

Stöd Flashback