0
$\begingroup$

I am interested in the case when we apply StringReplace to a string searching for two substrings where one is contained in the other and we define different replacement rules for each one.

A simple example:

 StringReplace["aabbaaabbcbcbcb",
{"aabb" -> "aab", "aaabb" -> "aaabb"}]

Here what we want is to replace "aabb" with "aab" except when "aabb" is part of "aaabb", when we want to do nothing.

This code gives us what we want, namely

aabaaabbcbcbcb

, but how does it achieve this?

Clearly it doesn't go through all substrings of length 4 starting from the left and replacing any that are "aabb" with "aab". So what does it do?

Edit: the documentation for StringReplace states as follows:

"StringReplace goes through a string, testing substrings that start at each successive character position. On each substring, it tries in turn each of the transformation rules you have specified. If any of the rules apply, it replaces the substring, then continues to go through the string, starting at the character position after the end of the substring."

The emphasis here is by me. These words do not describe fully what actually happens. If they did, then when the program got to consider substrings starting at the fifth character in "aabbaaabbcbcbcb", trying in turn "each of the transformation rules" to check whether any of them "applied", it would find that rule 2 applies and rule 1 doesn't, so it would apply rule 2 which is to do nothing. Moving on to the sixth character, it would find that rule 1 applies and rule 2 doesn't, so it would apply rule 1. The end result would be to replace "aabbaaabbcbcbcb" with "aabaaabcbcbcb". In actual fact the program gives "aabaaabbcbcbcb" as stated.

$\endgroup$
9
  • 1
    $\begingroup$ The procedure is described in the second paragraph in the documentation under "Details and Options". $\endgroup$
    – lericr
    Nov 6, 2023 at 20:39
  • $\begingroup$ It is described wrongly. If that were followed it would give a different output. See my edit. $\endgroup$
    – tell
    Nov 6, 2023 at 22:11
  • $\begingroup$ You didn't read it closely enough. Specifically, "then continues to go through the string, starting at the character position after the end of the substring" $\endgroup$
    – lericr
    Nov 6, 2023 at 22:23
  • $\begingroup$ To be explicit, once it's looked at characters 1-4, it'll use the first rule. It now starts with character 5. Once it's looked at characters 5-9, it'll recognize that the second rule needs to be applied. Once it's done that, it starts with charcter 10. It has no chance to back track to character 6 and detect that the first rule could have been applied to characters 6-9. $\endgroup$
    – lericr
    Nov 6, 2023 at 22:26
  • $\begingroup$ If it's looking at chars 1-4, neither rule applies. If it then moves to looking at chars 5-9, rule 1 applies on chars 5-8 but not 6-9, and rule 2 applies on neither. If at this point it were to carry out a replacement of chars 5-8 according to rule 1, it would change the double b into a single b. But it doesn't actually do this. $\endgroup$
    – tell
    Nov 6, 2023 at 22:50

1 Answer 1

1
$\begingroup$

Here's how I interpret the documentation:

1-1: "a", no match
1-2: "aa", no match
1-3: "aab", no match
1-4: "aabb", match rule "aabb"->"aab"
5-5: "a", no match
5-6: "aa", no match
5-7: "aaa", no match
5-8: "aaab", no match
5-9: "aaabb", match rule "aaabb"->"aaabb"
10-10: "c", no match
...
$\endgroup$
4
  • $\begingroup$ Thanks. I've got it now. You are right. $\endgroup$
    – tell
    Nov 6, 2023 at 23:05
  • $\begingroup$ The documentation should say "StringReplace goes through a string, testing substrings in order of length that start at each successive character position. On each substring, it tries in turn any of the transformation rules you have specified that act on substrings of the given length. If a rule applies, it replaces the substring and then continues to go through the string, starting at the character position after the end of the substring." $\endgroup$
    – tell
    Nov 6, 2023 at 23:11
  • $\begingroup$ This is because when it's checking starting from a given character, it doesn't ask "do any of these rules apply" when the rules test substrings that are of different lengths. $\endgroup$
    – tell
    Nov 6, 2023 at 23:12
  • $\begingroup$ But it does. Mabye I don't understand what you're saying, but I think my answer demonstrates exactly this. E.g. when checking characters 5-8 ("aaab"), it checked whether "aabb" matched and since it doesn't it checked whether "aaabb" matched, and it also doesn't match, so it moves on. Then when checking 5-9 ("aaabb"), it checks whether "aabb" matches and since it doesn't it checks "aaabb" and bingo, it matches, so it applies the rules and updates its starting position and continues. $\endgroup$
    – lericr
    Nov 6, 2023 at 23:47

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.