9
$\begingroup$

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?

$\endgroup$

4 Answers 4

4
$\begingroup$

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 :>.

$\endgroup$
8
  • $\begingroup$ Doesn't work for "E:\\job\\a\\000298.png". $\endgroup$ Commented Sep 15, 2018 at 5:08
  • $\begingroup$ @CarlWoll How about now? $\endgroup$ Commented Sep 15, 2018 at 5:11
  • $\begingroup$ Now it doesn't work for "E:\\job\\a\\000998.png". $\endgroup$ Commented Sep 15, 2018 at 5:14
  • $\begingroup$ @CarlWoll ah, your are right $\endgroup$ Commented Sep 15, 2018 at 5:17
  • 2
    $\begingroup$ StringReplace[string, x : RegularExpression["\\d*[02468](?=\\.)"] :> IntegerString[ToExpression[x] + 2, 10, 6]] is more concise.. $\endgroup$ Commented Sep 15, 2018 at 11:06
7
$\begingroup$

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"}

$\endgroup$
4
$\begingroup$
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

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

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 *) 
$\endgroup$
8
  • $\begingroup$ 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. $\endgroup$ Commented Sep 14, 2018 at 23:16
  • $\begingroup$ @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? $\endgroup$ Commented Sep 14, 2018 at 23:28
  • $\begingroup$ 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. $\endgroup$ Commented Sep 14, 2018 at 23:32
  • $\begingroup$ It doesn't work for "/job/a/000258.png" where f returns "/job/a/0002510.png". $\endgroup$ Commented Sep 14, 2018 at 23:35
  • $\begingroup$ @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. $\endgroup$ Commented Sep 14, 2018 at 23:37

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.