7

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.

István Zachar
  • 47,032
  • 20
  • 143
  • 291
user4714
  • 73
  • 3

4 Answers4

7

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.

rm -rf
  • 88,781
  • 21
  • 293
  • 472
5

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.

chris
  • 22,860
  • 5
  • 60
  • 149
kglr
  • 394,356
  • 18
  • 477
  • 896
5

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]}]
wxffles
  • 14,246
  • 1
  • 43
  • 75
3

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]
chris
  • 22,860
  • 5
  • 60
  • 149
  • 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. – rm -rf Nov 19 '12 at 22:09
  • @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. – chris Nov 19 '12 at 22:10
  • @chris He may have more than 99 pdf files in his directory. I recommend StringTake[#, First@First@StringPosition[#, "."] - StringLength[#]] & – VF1 Nov 19 '12 at 22:12
  • How to use string patterns to do this ? – user4714 Nov 19 '12 at 22:13
  • 1
    @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. – VF1 Nov 19 '12 at 22:13
  • @VF1 thanks but just for my learning purposes – user4714 Nov 19 '12 at 22:14
  • @user4714 There's a whole guide in the docs for that. But, tbh, I find myself using RegularExpression[(* Regex *)] most of the time anyway. – VF1 Nov 19 '12 at 22:16