I have a long string list:

string = {"E:\\job\\a\\000251.png", "E:\\job\\a\\000252.png",
  "E:\\job\\a\\000253.png", "E:\\job\\a\\000254.png",
  "E:\\job\\a\\000255.png", "E:\\job\\a\\000256.png"}

Now, I want to add 2 to the file name base when the file base name is an even number. I mean, I hope to get such new string list:

string = {"E:\\job\\a\\000251.png", "E:\\job\\a\\000254.png",
  "E:\\job\\a\\000253.png", "E:\\job\\a\\000256.png",
  "E:\\job\\a\\000255.png", "E:\\job\\a\\000258.png"}

How to implement it?

up vote 4 down vote accepted

It seams that there has not been an answer involved with RegularExpression yet, which is quite efficient when dealing with patterns of strings.

StringReplace[string, x : RegularExpression["\\d*[02468]\\."] :> ToString[NumberForm[ToExpression[x] + 2, 5, NumberPadding -> "0"]]]
{"E:\\job\\a\\000251.png",
 "E:\\job\\a\\000254.png",
 "E:\\job\\a\\000253.png",
 "E:\\job\\a\\000256.png",
 "E:\\job\\a\\000255.png", 
 "E:\\job\\a\\000258.png"}

Update

As @yode pointed out in the comment, IntegerString is better here on the right-hand side of :>.

  • Doesn't work for "E:\\job\\a\\000298.png". – Carl Woll Sep 15 at 5:08
  • @CarlWoll How about now? – Αλέξανδρος Ζεγγ Sep 15 at 5:11
  • Now it doesn't work for "E:\\job\\a\\000998.png". – Carl Woll Sep 15 at 5:14
  • @CarlWoll ah, your are right – Αλέξανδρος Ζεγγ Sep 15 at 5:17
  • 2
    StringReplace[string, x : RegularExpression["\\d*[02468](?=\\.)"] :> IntegerString[ToExpression[x] + 2, 10, 6]] is more concise.. – yode Sep 15 at 11:06

You could create a helper function (the point of the helper function is to avoid calling FromDigits twice):

incString[s_] := With[{r = FromDigits[s]},
    If[EvenQ[r],
        IntegerString[r+2, 10, StringLength[s]],
        s
    ]
]

and then use this helper function in StringReplace:

StringReplace[
    string,
    i:DigitCharacter..~~".png" :> incString[i]<>".png"
]

{"E:\job\a\000251.png", "E:\job\a\000254.png", \ "E:\job\a\000253.png", "E:\job\a\000256.png", "E:\job\a\000255.png", \ "E:\job\a\000258.png"}

StringReplace[string, 
 a : NumberString ~~ "." /; EvenQ[FromDigits[a]] :> 
   StringPadLeft[IntegerString[FromDigits[a] + 2], StringLength@a, "0"] ~~ "."] 

{"E:\job\a\000251.png",
"E:\job\a\000254.png",
"E:\job\a\000253.png",
"E:\job\a\000256.png",
"E:\job\a\000255.png",
"E:\job\a\000258.png"}

Borrowing the three-argument IntegerString idea from Carl's answer with an alternative replacement rule:

StringReplace[string, a : NumberString ~~ "." :> With[{b = FromDigits @ a}, 
   IntegerString[b + 2 (1 - Mod[b, 2]), 10, StringLength @ a]] ~~ "."]

same result

  • Maybe more concise StringReplace[string, a : DigitCharacter ~~ "." /; EvenQ[FromDigits[a]] :> StringJoin[ToString[FromDigits[a] + 2]] ~~ "."] – yode Sep 14 at 20:23
  • see here please. – yode Sep 14 at 20:27
  • @yode, if you don't have elements like "E:\job\a\000258.png" in your string list your more concise version would work too. – kglr Sep 14 at 20:53

Here is an approach without StringReplace. It is one function f that first destructures the file-name and has two more definitions: one for files with an even number and one for all others.

ClearAll[f]
f[str_String] := f[{str, DirectoryName[str], FileBaseName[str], FileExtension[str]}];

f[{str_, dir_, name_, ext_} /; ToExpression[name, InputForm, EvenQ]] :=
   With[{
     num = IntegerString[FromDigits[name] + 2, 10, StringLength[name]]
   }, FileNameJoin[{dir, num <> "." <> ext}]];

f[{str_, __}] := str

Now better test it properly since my last version was completely screwed up. I need to make Linux filenames from your strings since otherwise, Mathematica's file functions don't work here. On your Windows machine, this should not be necessary.

string = {"E:\\job\\a\\000251.png", "E:\\job\\a\\000252.png", 
  "E:\\job\\a\\000253.png", "E:\\job\\a\\000254.png", 
  "E:\\job\\a\\000255.png", "E:\\job\\a\\000256.png"};
string = StringReplace[string, {"E:\\" :> "/", "\\" :> "/"}]

f/@string//Column
(* 
/job/a/000251.png
/job/a/000254.png
/job/a/000253.png
/job/a/000256.png
/job/a/000255.png
/job/a/000258.png 
*)
  • I have the greatest admiration for your contributions. I am trying to follow your answer but I believe there is an error in the second definition of f. num is defined as a local constant in With but never used in the output. I would also appreciate it if you would show how to use f for the given example. – Jack LaVigne Sep 14 at 23:16
  • @JackLaVigne Oh my goodness. There was so much wrong in my code because I didn't clear f for testing. Thank you for paying attention! Would you test if it works on windows with the original definition of strings? – halirutan Sep 14 at 23:28
  • Works fine in Windows. I was thinking I had to Map the function f`` over string`. Thank you for the update and example. It is clear to me now. – Jack LaVigne Sep 14 at 23:32
  • It doesn't work for "/job/a/000258.png" where f returns "/job/a/0002510.png". – Carl Woll Sep 14 at 23:35
  • @CarlWoll If you are on Windows, then this seems to be expected. Filename separators are OS specific and Mathematica's functions don't work if you are on Windows and try Unix files. – halirutan Sep 14 at 23:37

Your Answer

 
discard

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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