在Python中给定索引处的给定字符串中插入一些字符串


76

我是Python的新手,面临一个问题:如何在已经存在的字符串中插入一些字段?

例如,假设我从任何包含以下内容的文件中读取了一行:

line = "Name Age Group Class Profession"

现在,我必须在Class字段之前的同一行中多插入3rd Field(Group)3次。这意味着输出线应为:

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

我可以轻松地检索第三个字段(使用split方法),但是请让我知道插入字符串的最简单方法吗?

Answers:


138

一个经常咬住新Python程序员的重要要点,但其他张贴者却没有明确指出:Python中的字符串是不可变的-您永远都不能就地对其进行修改。

在Python中使用字符串时,您需要重新培训自己,以便不要思考“如何修改此字符串?”。取而代之的是,您在考虑“如何创建一个新字符串,其中包含我已经得到的一些内容?”


36
这实际上并不能为Python没有索引插入或替换辩解!输出可能只是包含所需结果的新字符串。
Codie CodeMonkey 2013年

8
Python Zen中的@CodieCodeMonkey提到“显式优于隐式”。您希望开发人员知道他将要处理副本。否则,他肯定会遇到对象身份问题,这将使调试工作受挫。思维字符串-认为功能。
Zakum

10
@Zakum,我明白你的意思,但是有一些先例,例如str.strip()。不仔细阅读文档的开发人员可能会认为strip()在原始文档上运行。
Codie CodeMonkey

2
无需单行代码就可以回答问题。正确心态的力量。
jchnxu

2
"how can I create a new string that has some pieces from this one I've already gotten?"好的,但是如何
挪威

120

为了将来的“新手”解决这个问题,我认为一个快速的答案很合适。

就像bgporter所说:Python字符串是不可变的,因此,要修改字符串,您必须利用已经拥有的部分。

在下面的例子中我插入'Fu''Kong Panda',创建'Kong Fu Panda'

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

在上面的示例中,我使用索引值将字符串“切片”为2个子字符串:1个包含插入索引之前的子字符串,另一个包含其余部分。然后,我只是在两者之间添加所需的字符串,然后在另一个字符串中插入一个字符串。

Python的切片表示法很好地解释了字符串切片的主题。


39
好的答案,但是我相信这部电影的标题被拼写为“功夫熊猫”
James Vickery

8
实际上,“拼写”和“拼写”都是正确的。“拼写”是英国的拼写。“拼写”仅在美国是不可接受的,因为“ muh,'farming”。它随方言的不同而不同,并且“拼写”与“拼写”一样古老。例如,是“问一个问题”还是“问一个问题”?答案是两者-两者都已经有近2000年的历史了,在这两者中,我相信“ ax”首先出现;“问”只是比较流行。
Matthew T. Scarbrough

1
建议find()将返回第一个匹配项的起始索引,-1如果未找到搜索字符串,则将返回。因此,这不会推广到感兴趣的字符串(在这种情况下Panda)可能多次出现或根本不出现的情况。
tony_tiger

18

我知道这是恶意的,但是恕我直言,简单的方法是:

def insert (source_str, insert_str, pos):
    return source_str[:pos]+insert_str+source_str[pos:]

2
这是什么
恶意的

1
@sehe它使用字符串连接,效率不是很高
Rob Smallshire

谢谢,我希望您对答案进行澄清。并非每个人都会理解其不利之处,这对人们了解它很有用:)
sehe

@RobSmallshire什么是更有效的方法?
雅各布·琼斯

@JacobJones使用str的join方法可能会更高效,从而避免产生较大的中间结果。return''.join(((source_str [:pos],insert_str,source_str [pos:]))
Rob Smallshire

7
line='Name Age Group Class Profession'
arr = line.split()
for i in range(3):
    arr.insert(2, arr[2])
print(' '.join(arr))

str.join()的优点是减少了内存使用,因为它不会创建中间字符串(尽管IIRC已在最新版本的CPython / PyPy中进行了优化)。另一方面,当仅合并少数几个字符串时,它比连接要慢,因此对于处理大型字符串或当您不得不执行大量串联时最有用。在Python 3.6下,当替换次数固定时,您可以使用f字符串代替串联来节省一些额外的CPU周期(例如,f'{source_str [:pos]} {insert_str} {source_str [pos:]}' )。
kgriffs

4

做这件事有很多种方法:

一种方法是使用切片:

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

另一种方法是使用正则表达式:

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

4

我在进行DNA分配时遇到了类似的问题,我使用了bgporter的建议来回答它。这是我创建新字符串的函数...

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

1

实作

下面的函数将允许您将一个字符串插入另一字符串:

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.__name__ 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.__name__ + ":  "
            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.__name__ + ":  "
        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)

用法

下面的代码演示了如何调用str_insert前面给出的函数

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

关于缺乏就地修改能力的警告

上面的函数均不会修改字符串“就地”。每个函数都返回字符串的修改后的副本,但是原始字符串保持不变。

例如,

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

0

在其他位于字符串的其他位置插入字符串的答案

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

注意:已经回答了stackoverflow.com/questions/53168288/…,因为那里的回答被禁用并且被欺骗了
pavan kumar
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.