YEMyslf
YEMyslf

Reputation: 447

remove date from filename programmatically

I'm trying to find a solution to strip some dates out of filenames programmatically. My files have the following format:

net_20110909_servercleanup.pdf

or

net_servercleanup_20110909.pdf

I've used the solution posted below (found on Stack Overflow also) to update some of the filenames but I would ideally have one solution that could update all files in my directories. I'd like to strip the date and one of the underscores out so the final file looks like this:

net_servercleanup.pdf

I'd like to do this from a batch file or PowerShell. I've seen some solutions that accomplish something like this using RegEx but I don't know enough about them to create something that will work. Any suggestions on how to accomplish this?

$filelist = (get-childitem c:\folder | Where-Object {$_.mode -match "a"} | foreach-object      {$_.name})
foreach ($file in $filelist)
{
    $len = $file.length
    $newname = $file.substring(0,$len -13)
    $newname = $newname + '.txt'
    Rename-Item C:\folder\$file $newname
    clear-variable newname, len
}

Upvotes: 1

Views: 3782

Answers (5)

MC ND
MC ND

Reputation: 70923

As this is also tagged as batch,

This code uses a for /f command to remove the numbers and underscores from the filename, keeping the first and second remaining elements joined with an underscore and then renames the file.

@echo off
    setlocal enableextensions disabledelayedexpansion

    for /r "c:\some\folder" %%f in ("net_*.pdf"
    ) do for /f "tokens=1,2 delims=_0123456789" %%a in ("%%~nf"
    ) do echo ren "%%~ff" "%%a_%%b%%~xf"

For testing, ren command is prefixed with a echo command. If the output is correct, remove the echo

Of course, if more than a matching file is found inside a folder, as it is impossible to have two files with the same name inside the same folder, the rename operation will fail for second or later files inside the same folder.

Upvotes: 1

Alexander Obersht
Alexander Obersht

Reputation: 3275

PowerShell, untested but should work:

$filelist = Get-ChildItem C:\folder | Where-Object {$_.Mode -match "a"} `
    | Foreach-Object {$_.FullName}

foreach ($fullpath in $filelist)
{
    $newpath = $fullpath -replace "_(19|20)[0-9]{6}"
    Rename-Item -Path $fullpath -NewName $newpath -WhatIf
}

The _(19|20)[0-9]{6} regular expression matches the following pattern: leading "_" followed by "19" or "20" and then any six digits. If you have file names where date does not strictly match your example, you may need to modify the regex to catch them all.

The -WhatIf switch allows you to do a "dry run" i.e. test cmdlets like Remove-Item without actually performing any file operations. Remove it when everything looks OK and you are ready to proceed with actual renaming.

Upvotes: 1

Ria
Ria

Reputation: 10347

try this regex:

_\d{8}

and replace with empty. this matchs _20110909 in

net_20110909_servercleanup.pdf or net_servercleanup_20110909.pdf

and result is net_servercleanup.pdf.

Upvotes: 1

StephenP
StephenP

Reputation: 4081

If you know that your filenames will always be of the form you mentioned you can just remove the underscore and 8 digits. Try this:

get-childitem c:\folder | Where-Object {$_.mode -match "a"} | foreach-object {
  rename-item $_.FullName ($_.FullName -replace '_\d{8}') -WhatIF
}

Remove the -whatif to actually perform the rename. the -replace parameter takes a regex that matches an underscore followed by 8 digits. Since you do not specify what to replace the match with, it is replaced with an empty string.

Note that this renames all of the files to the same filename causing Rename-Item to error if the file exists. If these are in nested subfolders and you want to iterate through them all you need to add a -Recursive parameter to get-childitem.

Upvotes: 1

DarkPotatoKing
DarkPotatoKing

Reputation: 499

I don't know what that language(?) is, but in C++, I'd do it by separating it into pieces based on your separator (this case, an underscore). Basically, I'd get the substring from the start to the character before the first underscore, store it into a stream (stringstream to be exact), get substring from the character after the first underscore to the character before the second underscore, ... , and so on. and then from the stream, I'd get the pieces one by one and check if it is an integer, if it is an integer then I discard it, otherwise it is appended to a string, if the string is not empty then I append a separator (an underscrore) before adding the piece.

I could write the code in c++ but I'm not sure if that would help

Upvotes: 1

Related Questions