7
$\begingroup$

I am trying to make the following:

StringReplace[{"A4", "A#3"}, {"A" ~~ x_ -> "B" ~~ x}]

This should replace A4 by B4 but leave A#3 untouched. How can I do that? I tried to use ? and /; with a test for whether or not the _ is a number string as follows:

StringReplace[{"A4","A#3"}, {"A" ~~ x_?StringMatchQ[x_, NumberString] -> "B" ~~ x}]

But it doesn't work. I don't know how to make the syntax work for this.

$\endgroup$

3 Answers 3

8
$\begingroup$

You've mixed up the usage of PatternTest (?) and Condition (/;). Here're 4 approaches, please read the document carefully to understand why they work:

StringReplace[{"A4", "A#3"}, {"A" ~~ x_?(StringMatchQ[#, NumberString] &) :> "B" <> x}]
(* {"B4", "A#3"} *)

StringReplace[{"A4", "A#3"}, {"A" ~~ x_?(StringMatchQ[NumberString]) :> "B" <> x}]
(* {"B4", "A#3"} *)

StringReplace[{"A4", "A#3"}, {"A" ~~ x_ /; StringMatchQ[x, NumberString] :> "B" <> x}]
(* {"B4", "A#3"} *)

StringReplace[{"A4", "A#3"}, {"A" ~~ x : NumberString :> "B" <> x}]
(* {"B4", "A#3"} *)

Remark

  1. Though StringExpression (~~) can be used in right hand side (RHS) of a rule, I've used StringJoin (<>) instead in code above because it's a better choice. See this and this post for more info.

  2. I've used RuleDelayed (:>) instead of Rule (->), because the RHS of rule cannot be evaluated immediately when <> is used instead of ~~.

  3. Even if ~~ is used in the RHS of rule, :> is still a better choice for your problem. Just try the following sample:

    x = 123;
    StringReplace[{"A4", "A#3"}, {"A" ~~ x : NumberString -> "B" ~~ x}]
    (* {"B" ~~ 123, "A#3"} *)
    
    StringReplace[{"A4", "A#3"}, {"A" ~~ x : NumberString :> "B" ~~ x}]
    (* {"B4", "A#3"} *)
    
$\endgroup$
3
  • $\begingroup$ When we apply (StringMatchQ[#, NumberString] &, this works like a function applied in x_? It's as if it were (StringMatchQ[x_, NumberString]? The syntax looks so weird to me, we are calling the "variable" x_ and then telling it to apply this "function" callling it something else, namely #. $\endgroup$
    – Red Banana
    Commented Mar 11 at 6:58
  • 2
    $\begingroup$ @RedBanana Please notice ? is just a shorthand for PatternTest, so x_?(StringMatchQ[#, NumberString] &) is equivalent to PatternTest[x_, StringMatchQ[#, NumberString] &]. In other words, PatternTest is a function whose first argument is a pattern and last argument is a function relationship that will be used to test the expression matching the pattern in first argument. The design is somewhat similar to Select, NestWhile, etc., you can compare them. $\endgroup$
    – xzczd
    Commented Mar 11 at 7:08
  • $\begingroup$ @RedBanana Ah I've made an improper statement about StringExpression (~~), it can actually be used in right hand side of rule. But still, StringJoin is a better choice, see the new-added links. $\endgroup$
    – xzczd
    Commented Mar 11 at 8:24
6
$\begingroup$

In this case maybe consider a RegularExpression

StringReplace[{"A4", "A#3"}, RegularExpression["(A)(\\d)"] :> "B$2"]

(* {"B4", "A#3"} *) 

Or even(!)

StringReplace[{"A4", "A#3"}, RegularExpression["(A)(\\d)"] :> 
    FromCharacterCode[ToCharacterCode["$1"] + 1] <> "$2"]

(* {"B4", "A#3"} *) 
$\endgroup$
2
$\begingroup$
list = {"A4", "A#3"};

Map[StringJoin, Characters[list] /. {"A", d_?DigitQ, ___} :> {"B", d}]

{"B4", "A#3"}

$\endgroup$

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.