Problems with string and lists (searching and replaceing)

Alex Martelli aleax at aleax.it
Mon Sep 22 08:49:24 EDT 2003


jblazi wrote:

> I should like to search certain characters in a string and when they are
> found, I want to replace other characters in other strings that are at
> the same position (for a very simply mastermind game) for my pupils.
> 
> This very simple thing does not seem simple at all.
> 
> If I use strings, I cannot replace their parts (though I can use
> string.find for the searching). I think it is a bad idea that strings are
> not mutable, but I suspect that this has been discussed here for ages.

Not really (most of us appear to have no problems with immutable
strings).  And indeed I don't see what's complicated with your task,
at all.  Suppose the string you're "searching certain characters in"
is held by variable "searched_string", the characters you are
searching in (any sequence, list or other) variable "characters",
the "other strings" are (e.g.) all the items of list "otherstrings",
and finally the replacement characters are in dictionary "replacers"
indexed by the found characters and with a default of say '*' when
a found character is not a key in "replacers".  Note that all of
these or similar hypotheses are obviously needed whether strings
are mutable or not.

Now, if strings were mutable, the obvious solution (avoiding
exceptions, as you asked) might be:

for c in characters:
    where = searched_string.find(c)
    if where<0: continue
    replace_with = replacers.get(c, '*')
    for another in otherstrings:
        if where < len(another):
            another[where] = replace_with

Now since strings are NOT mutable, you need to change this to:

for c in characters:
    where = searched_string.find(c)
    if where<0: continue
    replace_with = replacers.get(c, '*')
    for i, another in enumerate(otherstrings):
        otherstrings[i] = another[:where] + replace_with + another[where+1:]

i.e, keep track of the index and set there another string build of
three parts -- preceding, replace_with, succeeding.  In this case
you do not have to ensure that where<len(another) -- if that
condition does not hold then replace_with will just be "appended"
to the "other string" (slicing is more tolerant than indexing).  If
you want the same semantics as above (no change to "other strings"
that are shorter than the 'where' point requires) then you'll just
have to add the same guard in this second case, of course.

Basically, the change from "x[y]=z" to "x=x[:y]+z+x[y+1:]" is just
not "traumatic" enough, in my opinion, to warrant considering this
a seriously complicated problem ("not seem simple at all").  If
you need to explain it to beginners by analogy: imagine you have an
original document that you're not allowed to alter, for example
because that document is bound and you don't want to, or cannot,
break its binding; despite this, you are requested to "change page
4 into this one" to make a new version.  Then, just "photocopy" 
pages 1 to 3, and pages 5 and following, and in the new version 
collate (first) the copies of original pages 1 to 3, (then)
the new "this one", and (finally) the copies of pages 5 and 
following of the original document.  Since not all documents one
meets in real life come in "flexible" bindings where one can
remove and replace pages, the analogy should be quite clear, IMHO.


Alex






More information about the Python-list mailing list