1
$\begingroup$

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[[1]], "A" <> # & /@ ToString
/@ Range[Length @ posList[[1]]]]]]
(*
 {[,A1,A2,],A3,B,[,A4,A5,],B,B,[,A6,A7,],B,[,A8,A9,],C,C,C}
*)
ReplacePart[sample2, Thread[Rule[List /@ posList[[2]], "B" <> # & /@ ToString
/@ Range[Length @ posList[[2]]]]]]
(*
 {[,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.

$\endgroup$
4
  • 2
    $\begingroup$ 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. $\endgroup$ Jun 18, 2013 at 8:37
  • $\begingroup$ @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[11] and Input[12] 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 $\endgroup$ Jun 18, 2013 at 9:19
  • $\begingroup$ @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. $\endgroup$ Jun 18, 2013 at 9:22
  • $\begingroup$ @SimonWoods I need your suggestions and comments about this question in formatting. meta.mathematica.stackexchange.com/questions/1027/ $\endgroup$ Jun 19, 2013 at 3:59

3 Answers 3

7
$\begingroup$

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"

With additional short-hands for brevity:

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"
$\endgroup$
6
  • $\begingroup$ This is great, now I feel ashamed. :) $\endgroup$
    – Kuba
    Jun 18, 2013 at 12:03
  • $\begingroup$ @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. $\endgroup$
    – Mr.Wizard
    Jun 18, 2013 at 12:07
  • $\begingroup$ 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[#]&/@ $\endgroup$
    – Kuba
    Jun 18, 2013 at 12:11
  • $\begingroup$ @Kuba Thanks. :-) $\endgroup$
    – Mr.Wizard
    Jun 18, 2013 at 12:11
  • 1
    $\begingroup$ @Kuba Examples one and two might interest you, related to that count method. $\endgroup$
    – Mr.Wizard
    Jun 18, 2013 at 12:20
3
$\begingroup$

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]
 ]

0. Answer to Your case

 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.

$\endgroup$
6
  • $\begingroup$ 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/… $\endgroup$ Jun 18, 2013 at 7:09
  • $\begingroup$ 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. $\endgroup$ Jun 18, 2013 at 10:20
  • $\begingroup$ @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. $\endgroup$
    – Kuba
    Jun 18, 2013 at 10:24
  • $\begingroup$ 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 $\endgroup$ Jun 18, 2013 at 10:32
  • $\begingroup$ @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. $\endgroup$
    – Kuba
    Jun 18, 2013 at 10:40
2
$\begingroup$

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"  *)
$\endgroup$
1
  • $\begingroup$ 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. $\endgroup$
    – Mr.Wizard
    Jun 19, 2013 at 11:39

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.