web-dev-qa-db-fra.com

Insérer une chaîne dans une chaîne donnée à un index donné en Python

Je suis un débutant en Python confronté à un problème: comment insérer des champs dans une chaîne déjà existante?

Par exemple, supposons que j'ai lu une ligne de n'importe quel fichier contenant:

line = "Name Age Group Class Profession"

Maintenant, je dois insérer le 3ème champ (groupe) 3 fois plus dans la même ligne avant le champ de classe. Cela signifie que la ligne de sortie devrait être: 

output_line = "Name Age Group Group Group Group Class Profession"

Je peux récupérer le 3ème champ facilement (en utilisant la méthode split), mais s'il vous plaît laissez-moi savoir le moyen le plus simple d'insérer dans la chaîne?

48
james

Un point important qui mord souvent les nouveaux programmeurs Python mais les autres affiches n’ont pas expliqué explicitement est que les chaînes en Python sont immuables - vous ne pouvez jamais les modifier sur place. 

Vous devez vous recycler lorsque vous travaillez avec des chaînes en Python afin qu'au lieu de penser, "Comment puis-je modifier cette chaîne?" à la place, vous pensez "comment puis-je créer une nouvelle chaîne qui a quelques morceaux de celui-ci que j'ai déjà obtenu?"

99
bgporter

Pour le bien des futurs «débutants» qui s’attaqueront à ce problème, je pense qu’une réponse rapide serait appropriée à ce sujet.

Comme bgporter dit: Les chaînes Python sont immuables, et donc, pour modifier une chaîne, vous devez utiliser les morceaux que vous avez déjà.

Dans l'exemple suivant, j'insère 'Fu' dans 'Kong Panda' pour créer 'Kong Fu Panda'

>>> line = 'Kong Panda'
>>> index = line.find('Panda')
>>> output_line = line[:index] + 'Fu ' + line[index:]
>>> output_line
'Kong Fu Panda'

Dans l'exemple ci-dessus, j'ai utilisé la valeur d'index pour "découper" la chaîne en 2 sous-chaînes: 1 contenant la sous-chaîne avant l'index d'insertion, et l'autre contenant le reste . Ensuite, j'ajoute simplement la chaîne souhaitée. entre les deux et voilà, nous avons inséré une chaîne dans une autre.

La notation slice de Python a une excellente réponse expliquant le sujet du découpage en chaîne.

75
Ben Avnon

Je sais que c'est malapropos, mais IMHO moyen facile est:

def insert (source_str, insert_str, pos):
    return source_str[:pos]+insert_str+source_str[pos:]
11
Sim Mak
line='Name Age Group Class Profession'
arr = line.split()
for i in range(3):
    arr.insert(2, arr[2])
print(' '.join(arr))
7
Michał Niklas

Il y a plusieurs moyens de le faire:

Une façon consiste à utiliser le découpage en tranches:

>>> a="line=Name Age Group Class Profession"
>>> b=a.split()
>>> b[2:2]=[b[2]]*3
>>> b
['line=Name', 'Age', 'Group', 'Group', 'Group', 'Group', 'Class', 'Profession']
>>> a=" ".join(b)
>>> a
'line=Name Age Group Group Group Group Class Profession'

Une autre serait d'utiliser des expressions régulières:

>>> import re
>>> a=re.sub(r"(\S+\s+\S+\s+)(\S+\s+)(.*)", r"\1\2\2\2\2\3", a)
>>> a
'line=Name Age Group Group Group Group Class Profession'
3
Tim Pietzcker

J'avais un problème similaire pour mon assignation d'ADN et j'ai utilisé le conseil de bgporter pour y répondre. Voici ma fonction qui crée une nouvelle chaîne ...

def insert_sequence(str1, str2, int):
    """ (str1, str2, int) -> str

    Return the DNA sequence obtained by inserting the 
    second DNA sequence into the first DNA sequence 
    at the given index.

    >>> insert_sequence('CCGG', 'AT', 2)
    CCATGG
    >>> insert_sequence('CCGG', 'AT', 3)
    CCGATG
    >>> insert_sequence('CCGG', 'AT', 4)
    CCGGAT
    >>> insert_sequence('CCGG', 'AT', 0)
    ATCCGG
    >>> insert_sequence('CCGGAATTGG', 'AT', 6)
    CCGGAAATTTGG

    """

    str1_split1 = str1[:int]
    str1_split2 = str1[int:]
    new_string = str1_split1 + str2 + str1_split2
    return new_string
3
Homam Bahrani

La mise en oeuvre

Les fonctions ci-dessous permettent d'insérer une chaîne dans une autre:

def str_insert(from_me, into_me, at):
    """
    Inserts the string <from_me> into <into_me>

    Input <at> must be an integer index of <into_me> or a substring of <into_me>

    Inserts <from_me> AFTER <at>, not before <at>

    Inputs <from_me> and <into_me> must have working __str__ methods defined.
    This is satisfied if they already are strings.

    If not already strings, <from_me>, <into_me> are converted into strings.

    If you try to insert an empty string, that's fine, and the result
    is no different from the original.

    In order to insert 'from_me' after nothing (insert at the beginning of the string) use:
        at = ''  or  at = 0
    """
    try:
        return str_insert_or_raise(from_me, into_me, at)
    except ValueError as err:
        serr = str(err)
        if (str_insert_or_raise.__in serr) and 'not found' in serr and '<at>' in serr:
            # if can't find where to insert stuff, don't bother to insert it
            # use str_insert_or_raise if you want an exception instead
            return into_me
        else:
            raise err

##############################################################

def str_insert_or_raise(from_me, into_me, at):
    """
    Inserts the string <from_me> into <into_me>

    Inserts <from_me> AFTER <at>, not before <at>

    Input <at> must be an integer index of <into_me> or a substring of <into_me>

    If <at> is the string '15', that substring will be searched for,
    '15' will not be interpreted as an index/subscript.        

    Inputs <from_me> and <into_me> must have working __str__ methods defined.
    If not already strings, <from_me>, <into_me> are converted into strings. 

    If you try to insert something, but we cannot find the position where
    you said to insert it, then an exception is thrown guaranteed to at least
    contain the following three substrings:
        str_insert_or_raise.__name__
        'not found'
        '<at>'
    """
    try:
        if isinstance(at, int):
            return str_insert_by_int(from_me, into_me, at)
        # Below, the calls to str() work fine if <at> and <from_me> are already strings
        # it makes them strings if they are not already
        return str_insert_by_str(str(from_me), str(into_me), str(at))
    except ValueError as err:
        serr = str(err)
        if 'empty string' in serr:
            return into_me # We allow insertion of the empty string
        Elif ("<at>" in serr) and 'not found' in serr:
            msg_start = "In " + str_insert_or_raise.__+ ":  "
            msg = [msg_start, "\ninput ", "<at> string", " not found in ", "<into_me>",
                              "\ninput <",   str(at)  , "> not found in <", str(into_me), ">"]
            msg = ''.join(msg)
            raise ValueError(msg) from None
        else:
           raise err
#############################################################
def str_insert_by_str(from_me, into_me, at):
    """
    Inserts the string <from_me> into <into_me>

    puts 'from_me' AFTER 'at', not before 'at'
    For example,
        str_insert_or_raise(at = '2',  from_me = '0', into_me = '123')
    puts the zero after the 2, not before the 2
    The call returns '1203' not '1023'

    Throws exceptions if input arguments are not strings.

    Also, if <from_me> is empty or <at> is not a substring of <into_me> then
    an exception is raised.

    For fewer exceptions, use <str_insert_or_raise> instead.
    """
    try:
        s = into_me.replace(at, at + from_me, 1)
    except TypeError as terr: # inputs to replace are not strings
        msg_list = ['Inputs to function ', str_insert_by_str.__name__, '() must be strings']
        raise TypeError(''.join(msg_list)) from None
    # At the end of call to replace(), the '1'  indicates we will replace
    # the leftmost occurrence of <at>, instead of every occurrence of <at>
    if (s == into_me): # <at> string not found and/or <from_me> is the empty string
        msg_start = "In " + str_insert_by_str.__+ ":  "
        if from_me == '':
            msg = ''.join([msg_start, "attempted to insert an empty string"])
            raise ValueError(msg) from None
        raise ValueError(msg_start, "Input <at> string not found in <into_me>.",
                                    "\nUnable to determine where you want the substring inserted.") from None
    return s
##################################################
def str_insert_by_int(from_me, into_me, at):
    """
    * Inserts the string <from_me> into <into_me> at integer index <at>    
    * throws exceptions if input arguments are not strings.    
    * Also, throws an  exception if you try to insert the empty string    
    * If <at> is less than zero, <from_me> gets placed at the
      beginning of <into_me>    
    * If <at> is greater than the largest index of <into_me>,
      <from_me> gets placed after the end of <into_me>

    For fewer exceptions, use <str_insert_or_raise> instead.
    """
    at = into_me[:(at if at > 0 else 0)]
    return str_insert_by_str(from_me, into_me, at)

Usage

Le code ci-dessous montre comment appeler la fonction str_insert donnée précédemment 

def foo(*args):
    return args

F = 'F. '

s = 'Using the string \'John \' to specify where to make the insertion'
result = str_insert(from_me = F, into_me ='John Kennedy', at ='John ')
print(foo('\n\n', s, '\n', result))

s = 'Using an int returned by find(\'Ken\') to specify where to make the insertion'
index = 'John Kennedy'.find('Ken') # returns the position of the first letter of 'Ken', not the last letter
result = str_insert(from_me = F, into_me ='John Kennedy', at = index)
print(foo('\n\n', s, '\n', result))

s = 'Using an int (5) to specify where to make the insertion.'
result = str_insert(from_me = F, into_me ='John Kennedy', at = 5)
print(foo('\n\n', s, '\n', result))

s = "Looking for an 'at' string which does not exist"
result = str_insert(from_me = F, into_me ='John Kennedy', at ='x')
print(foo('\n\n', s, '\n', result))

s = ''.join(["Looking for the empty string.",
             "\nFind one immediately at the beginning of the string"])
result = str_insert(from_me = F, into_me ='John Kennedy', at = '')
print(foo('\n\n', s, '\n', result))

s = "Insert an empty string at index 3. No visible change"
result = str_insert(from_me = '', into_me = 'John Kennedy', at = 3)
print(foo('\n\n', s, '\n', result))    

for index in [-5, -1, 0, 1, 997, 999]:
    s = "index " + str(index)
    result = str_insert(from_me = F, into_me = 'John Kennedy', at = index)
    print(foo('\n\n', s, '\n', result))

Avertissement concernant le manque de capacité à modifier sur place

Aucune des fonctions ci-dessus ne modifiera une chaîne "sur place". Les fonctions renvoient chacune une copie modifiée de la chaîne, mais la chaîne d'origine reste intacte.

Par exemple,

s = ''.join(["Below is what we get when we forget ",
             "to overwrite the string with the value",
             " returned by str_insert_or_raise:"])

examp_str = 'John Kennedy'
str_insert('John ', F, examp_str)
print(foo('\n\n', s, '\n', examp_str))

# examp_str is still 'John Kennedy' without the F
1
Toothpick Anemone

Réponse pour Insérer les caractères de la chaîne dans les autres positions de chaîne

str1 = "ibuprofen"
str2 = "MEDICAL"
final_string=""
Value = 2
list2=[]
result=[str1[i:i+Value] for i in range(0, len(str1), Value)]
count = 0

for letter in result:
    if count < len(result)-1:
        final_string = letter + str2[count]
        list2.append(final_string)
    Elif ((len(result)-1)==count):
        list2.append(letter + str2[count:len(str2)])
        break
    count += 1

print(''.join(list2))
0
pavan kumar