# question

conversion1 : Convert "[AA]AB[AA]BB[AA]B[AA]CCC" to "[A1A2]A3B1[A4A5]B2B3[A6A7]B4[A8A9]CCC"

conversion2 : Convert "[AA]AB[AA]BB[AA]B[AA]CCC" to "[A1A2]AB1[A3A4]B2B3[A5A6]B4[A7A8]CCC"

where A is sensitive to "[]"

In conversion 2, both A and B (even C, though no more B or C in "[]") could be sensitive to "[]", we can control them.

And we can ignore the string in "[]".

# my tries

case1: String

sample1 = "[AA]AB[AA]BB[AA]B[AA]CCC"; pos = StringPosition[sample1, "A"];
StringReplacePart[sample1, ToString /@ pos, pos]

(*
[{2, 2}{3, 3}]{5, 5}B[{8, 8}{9, 9}]BB[{14, 14}{15, 15}]B[{19, 19}{20, 20}]CCC
*)


case2 List

sample2 = Characters @ sample1; pos = Position[sample2, "A"];
ReplacePart[sample2, Thread[Rule[List /@ pos, "A" <> # & /@ ToString /@ Range[Length @ pos]]]]

(*
{[,A1,A2,],A3,B,[,A4,A5,],B,B,[,A6,A7,],B,[,A8,A9,],C,C,C}
*)


# How about the case with multiple patterns.

case 3

pos = Position[sample2, "A" | "B"];


This is not good

ReplacePart[sample2, Thread[Rule[List /@ pos, ToString /@ Range[Length @ pos]]]];

posList = Position[sample2, #] & /@ {"A", "B"};


good for A and B separately

ReplacePart[sample2, Thread[Rule[List /@ posList[], "A" <> # & /@ ToString
/@ Range[Length @ posList[]]]]]

(*
{[,A1,A2,],A3,B,[,A4,A5,],B,B,[,A6,A7,],B,[,A8,A9,],C,C,C}
*)

ReplacePart[sample2, Thread[Rule[List /@ posList[], "B" <> # & /@ ToString
/@ Range[Length @ posList[]]]]]

(*
{[,A,A,],A,B1,[,A,A,],B2,B3,[,A,A,],B4,[,A,A,],C,C,C}
*)


How to combine those to get the result

{[,A1,A2,],A3,B1,[,A4,A5,],B2,B3,[,A6,A7,],B4,[,A8,A9,],C,C,C}

or more elegant way to do this?

Either string or list case is needed, and both of them in aswer is better.

• Please try to describe in words what you are trying to do, rather than expecting people to deduce it from an example. Also, there's no need for all the (* Input 10 ==< *) stuff - code in a code block will be understood to be input, it doesn't need extra signposts. – Simon Woods Jun 18 '13 at 8:37
• @SimonWoods ok, I'll develop it in the future, when they are not needed. Signposts are conceived to use in such case. How to combine Input and Input to get the result. As well as the case: multiple output results are pictures which do not follow the input but in the end of the post being a total image. This is one prevous example. mathematica.stackexchange.com/a/26932/6648 – HyperGroups Jun 18 '13 at 9:19
• @SimonWoods Sometimes, (maybe always...) I'm poor in judging how much words to use, and how much codes to show. In this case, Kuba's answer and comment catched on my this post's question broadly. – HyperGroups Jun 18 '13 at 9:22

Your replacements can be handled entirely by the StringReplace function with a little assistance from an external counter function.

A counter can be constructed merely with:

count[_] = 0;


This can then be incremented for arbitrary expressions:

++count[#] & /@ {"c", "b", "b", "b", "c", "a", "b"}

{1, 1, 2, 3, 2, 1, 4}


This method applied to your first replacement:

Module[{c},
c[_] = 0;
StringReplace[
"[AA]AB[AA]BB[AA]B[AA]CCC",
x : "A" | "B" :> x <> ToString[++c[x]]
]
]

"[A1A2]A3B1[A4A5]B2B3[A6A7]B4[A8A9]CCC"


Your second replacement adds a complication of context; one approach is a nested StringReplace:

Module[{c},
c[_] = 0;
StringReplace[
"[AA]AB[AA]BB[AA]B[AA]CCC",
{
sq : Shortest["[" ~~ __ ~~ "]"] :> StringReplace[sq, x : "A" :> x <> ToString[++c[x]]],
x : "B" :> x <> ToString[++c[x]]
}
]
]

"[A1A2]AB1[A3A4]B2B3[A5A6]B4[A7A8]CCC"


Module[{c, sr, rule},
c[_] = 0;
sr = StringReplace;
rule = x : # :> x <> ToString[++c[x]] &;
sr[
"[AA]AB[AA]BB[AA]B[AA]CCC",
{sq : Shortest["[" ~~ __ ~~ "]"] :> sr[sq, rule["A"]], rule["B"]}
]
]

"[A1A2]AB1[A3A4]B2B3[A5A6]B4[A7A8]CCC"

• This is great, now I feel ashamed. :) – Kuba Jun 18 '13 at 12:03
• @Kuba You should not! If this kind of programmatic string replacement (by which I mean code may be executed as part of the right-hand side) were not available your method would be a good alternative. – Mr.Wizard Jun 18 '13 at 12:07
• Yes, the fact that methods are different heartens :) But in such questions I usually start from replacement rules, this time I have failed. :) Big +1 for ++count[#]&/@ – Kuba Jun 18 '13 at 12:11
• @Kuba Thanks. :-) – Mr.Wizard Jun 18 '13 at 12:11
• @Kuba Examples one and two might interest you, related to that count method. – Mr.Wizard Jun 18 '13 at 12:20

# Generalisation

This code is a generalisation of what is wirtten in next two chapters (first and second converions):

genRep[string_, char_, patt_] := Module[{conRep, set, pos, rep},
conRep[$string_,$char_] := Module[{$pos,$rep},
$pos = StringPosition[$string, $char];$rep = Table[$char <> ToString@i, {i, Length@$pos}];
StringReplacePart[$string,$rep, \$pos] ];

set = StringCases[string, patt];
pos = StringPosition[string, patt];
rep = conRep[StringJoin@set, char];
set = StringCases[rep, patt];
StringReplacePart[string, set, pos] ]


It allows us to specify pattern which extracts parts of string we want to modify. But I have not tested it for more complicated patterns and I suspect it is not "well done" :)

genRep[string, "A", "[" ~~ Except["]"] .. ~~ "]"]
genRep[string, "A", "]" ~~ Except["]"] .. ~~ "["]

"[A1A2]AB[A3A4]BB[A5A6]B[A7A8]CCC"
"[AA]A1B[AA]BB[AA]B[AA]CCC"


# First type conversion:

Convert "[AA]AB[AA]BB[AA]B[AA]CCC" to "[A1A2]A3B1[A4A5]B2B3[A6A7]B4[A8A9]CCC"

I've created function which will replace given character:

conRep[string_, char_] := Module[{pos, rep},
pos = StringPosition[string, char];
rep = Table[char <> ToString@i, {i, Length@pos}];
StringReplacePart[string, rep, pos]
]


1. Character replacement.

string = "[AA]AB[AA]BB[AA]B[AA]CCC";

conRep[string, "A"]

"[A1A2]A3B[A4A5]BB[A6A7]B[A8A9]CCC"


2. Multiple characters. Put them in to 3rd Fold argument:

Fold[conRep, string, {"A", "B"}]

"[A1A2]A3B1[A4A5]B2B3[A6A7]B4[A8A9]CCC"


If list of replaced characters should be automatic You can use Characters and drop from there "[" etc.

3. String replacing works too:

conRep[string, "AA"]

"[AA1]AB[AA2]BB[AA3]B[AA4]CCC"


# Second type conversion:

Convert "[AA]AB[AA]BB[AA]B[AA]CCC" to "[A1A2]AB1[A3A4]B2B3[A5A6]B4[A7A8]CCC"

Basic idea is to extract terms inside "[ ]" and apply my previous functions to them. In Your question "A" is modyfied only inside "[ ]" and B is not "[]"-sensitive so later You can just apply first function.

 avRep[string_, char_] := Module[{set,pos,rep},
set = StringCases[string, "[" ~~ Except["]"] .. ~~ "]"];
pos = StringPosition[string, "[" ~~ Except["]"] .. ~~ "]"];
rep = conRep[StringJoin@set, char];
set = StringCases[rep, "[" ~~ Except["]"] .. ~~ "]"];
StringReplacePart[string, set, pos]
]


 string = "[AA]AB[AA]BB[AA]B[AA]CCC"
avRep[#, "A"] &@string
conRep[#, "B"] &@%

"[AA]AB[AA]BB[AA]B[AA]CCC"
"[A1A2]AB[A3A4]BB[A5A6]B[A7A8]CCC"
"[A1A2]AB1[A3A4]B2B3[A5A6]B4[A7A8]CCC"


Fold, strings works with this function as well.

• good to use Fold. In conversion 2, both A and B(even C, though no more B or C in "[ ]") could be sensitive to "[ ]", we can control them. or Ignore the string in "[ ]", my previous question maybe related little: mathematica.stackexchange.com/questions/27144/… – HyperGroups Jun 18 '13 at 7:09
• The use of Except like that in the example Remove tags in Html. One about formatting: Why do you(and some people)do not comment out the output in the blockquotes? with (**) we can directly copy the whole codes/answer to Notebook, and Divide cells to evaluate. – HyperGroups Jun 18 '13 at 10:20
• @HyperGroups I assume You do not have to copy output. All is in the input. Evaluate it and test if it match what I have put in blockquotes. But indeed, I usually have doubts about my formatting. – Kuba Jun 18 '13 at 10:24
• Yes, If not copy outputs, I have to copy Input codes one by one when there are Ouputs between them. And I confused with formatting much, in one of my previous answer, my blockquotes was edited by comment out. mathematica.stackexchange.com/a/26868/6648 – HyperGroups Jun 18 '13 at 10:32
• @HyperGroups There is a discussion on meta about formatting (which I am not able to find now) There are couple of ways to format output. This one is preseted there by Artes. – Kuba Jun 18 '13 at 10:40

Just for fun, here's a modified version of Mr Wizard's code which deals with the square brackets in a single StringReplace. The idea is to make the matching of "A" conditonal on a boolean symbol whose value flips between true and false everytime a "[" or "]" is encountered. The flipping is done inside a Condition which always fails, so that the brackets themselves don't get replaced. (Thanks to Mr Wizard for pointing out that the condition will fail if the test evaluates to Null.)

It's obviously not as flexible or general as nesting StringReplace but might be pleasing to those who like complex patterns...

Module[{c, q = False}, c[_] = 0;
StringReplace["[AA]AB[AA]BB[AA]B[AA]CCC",
x : ("[" | "]" /; (q = ! q;)) | ("A" /; q) | "B" :>
x <> ToString[++c[x]]]]

(*  "[A1A2]AB1[A3A4]B2B3[A5A6]B4[A7A8]CCC"  *)

• That's pretty clever! I don't know that I would be comfortable using this in practice, but that could be only because I haven't been exposed to it before and I need time for it to be familiar. It's certainly the style of coding I appreciate however, so a hearty +1. – Mr.Wizard Jun 19 '13 at 11:39