7
$\begingroup$

I have a directory of files with the pattern: "some_number.some_name.pdf" I want to remove the "some_number." part from all the files. How to do that? There are a few commands in my head: FileNames, Map, etc. But I don't know how to chain them together to achieve the task.

Thanks in advance.

$\endgroup$
2
  • 2
    $\begingroup$ Try ?Rename*; ?StringR* and give it a shot. Its not a very difficult problem really. $\endgroup$
    – chris
    Nov 19, 2012 at 21:59
  • $\begingroup$ Other useful functions involve ?Regular* $\endgroup$
    – chris
    Nov 19, 2012 at 22:12

4 Answers 4

7
$\begingroup$

As I mentioned in a comment, using string patterns makes for lot cleaner code. Here's a simple way to do it using StringCases:

changeFileName = StringCases[#, NumberString ~~ "." ~~ f__ :> f] &;
changeFileName@"1234.name.pdf"
(* {"name.pdf"} *)

If you have a list of file names, map the above onto the list.

You can progressively build upon this for more complicated filename patterns. However, for the requirements in the question, this is adequate.

$\endgroup$
5
$\begingroup$

A pure function to make the changes to a filename string:

 fileNameChangeF = StringJoin@ Riffle[
   Pick[#, StringFreeQ[#, __ ~~ "_" ~~ NumberString] & /@ #] &@#,"."] &@
      StringSplit[#, "."] &

example:

 filenameList = {"abc_1234.xyz_name1.pdf",   "abc_1234.xyz_222.aaa_name2.pdf",
      "some_name.pdf"}
 fileNameChangeF/@filenameList
 (* {"xyz_name1.pdf", "aaa_name2.pdf", "some_name.pdf"} *)

EDIT: what the function does step-by-step:

 filenameList[[1]] (* input filename string *)
 (* "abc_1234.xyz_name1.pdf" *)
 StringSplit[#, "."] &[%] (* split at "."s *)
 (* {"abc_1234","xyz_name1","pdf"} *)
 StringFreeQ[#, __ ~~ "_" ~~ NumberString] & /@ % 
    (* find the parts free of the pattern *)
 (*{False,True,True} *)
 Pick[%%, %] (* pick those parts *)
 (* {"xyz_name1","pdf"}*)
 Riffle[%, "."] (* insert "."s back in *)
 (* {"xyz_name1",".","pdf"} *)
 StringJoin[%] (* ... and join *)
 (* "xyz_name1.pdf" *)

Mapped to a list of filenames fileNameChangeF/@filenameList, it does the same operations on each filename.

$\endgroup$
6
  • $\begingroup$ obviously a good answer but pretty scary nonetheless! $\endgroup$
    – chris
    Nov 19, 2012 at 22:20
  • $\begingroup$ Wow when i fully understand this oneliner i'll learn some good stuff from Mathematica. Thanks ! $\endgroup$
    – user4714
    Nov 19, 2012 at 22:22
  • $\begingroup$ @chris, updated to make it dispell the scare :) $\endgroup$
    – kglr
    Nov 19, 2012 at 22:36
  • $\begingroup$ @kguler have you ever considered competing for the one-liner competition? :-) $\endgroup$
    – chris
    Nov 19, 2012 at 22:39
  • 1
    $\begingroup$ For guys who like regexes: RegularExpression["(?s).+_(\\d)+"] $\endgroup$ Nov 19, 2012 at 22:46
5
$\begingroup$

Here's how I'd do it. Hopefully it's general enough, and easy to understand.

Start by defining a base directory:

 base = "c:\\mse\\test\\";

I usually use Import to get a list of filenames. If you give it a directory name, it will return a list of all the files under that directory (including subdirectories):

original = Import[base]

{"1.alice.pdf", "2.bob.pdf", "30.charlie.pdf"}

Then we can use a string expressions and a rule to transform the names:

renamed = StringReplace[original, NumberString .. ~~ "." ~~ name__ ~~ ".pdf" ->
  name ~~ ".pdf"]

{"alice.pdf", "bob.pdf", "charlie.pdf"}

Finally take the two lists and rename the files. It's probably clearest to use a Table:

Table[RenameFile[base <> original[[i]], base <> renamed[[i]]], {i, Length[original]}]
$\endgroup$
1
  • 1
    $\begingroup$ For regex fans: StringReplace[original, RegularExpression["(\\d)+\\."] -> ""] $\endgroup$ Nov 20, 2012 at 0:05
3
$\begingroup$

Just for guidance, you could

SetDirectory["~/tmp/"]

ff = FileNames["*.pdf"]

{01.toto01.pdf,02.toto02.pdf}

Try it with a fake function to be sure

Map[RenameFile1[#, StringDrop[#, 3]] &, ff]

If it does what you want do it for real

Map[RenameFile[#, StringDrop[#, 3]] &, ff]
$\endgroup$
7
  • $\begingroup$ I would rather use string patterns to drop the prefix instead of StringDrop. The latter assumes that all prefixes are of the same length, which may not be true. $\endgroup$
    – rm -rf
    Nov 19, 2012 at 22:09
  • $\begingroup$ @rm-rf sure. I would rather not do it myself though and let the OP do what he wants ;-) Feel free to edit/remove my answer in any case. $\endgroup$
    – chris
    Nov 19, 2012 at 22:10
  • $\begingroup$ @chris He may have more than 99 pdf files in his directory. I recommend StringTake[#, First@First@StringPosition[#, "."] - StringLength[#]] & $\endgroup$
    – VF1
    Nov 19, 2012 at 22:12
  • $\begingroup$ How to use string patterns to do this ? $\endgroup$
    – user4714
    Nov 19, 2012 at 22:13
  • 1
    $\begingroup$ @user4714 I don't see why you would use patterns, since the numbers are always at the beginning of the string. There's no need to always use pattern matching. $\endgroup$
    – VF1
    Nov 19, 2012 at 22:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.