繁体   English   中英

在给定索引处将一些字符串插入给定字符串

[英]Insert some string into given string at given index

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

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

line = "Name Age Group Class Profession"

现在我必须在 Class 字段之前的同一行中再插入第三个字段(组)3次。 这意味着 output 行应该是:

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

我可以轻松检索第三个字段(使用split方法),但请告诉我插入字符串的最简单方法?

一个经常困扰 Python 新手但其他海报没有明确说明的重要一点是 Python 中的字符串是不可变的——你永远无法修改它们。

在 Python 中处理字符串时,您需要重新训练自己,这样就不必思考“我如何修改这个字符串?” 相反,你在想“我怎样才能创建一个新的字符串,其中包含我已经得到的一些片段?”

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

就像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 的切片符号有一个很好的答案来解释字符串切片的主题。

我知道这是不合理的,但恕我直言,简单的方法是:

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

我的 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

有几种方法可以做到这一点:

一种方法是使用切片:

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

实施

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

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

将字符串的字符插入到其他字符串位置的答案

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

这是一个简单的 function ,它在上面扩展以允许在索引处或字符串中的任何字符处插入。

def insert(src, ins, at, occurrence=1, before=False):
    '''Insert character(s) into a string at a given location.
    if the character doesn't exist, the original string will be returned.

    :parameters:
        src (str) = The source string.
        ins (str) = The character(s) to insert.
        at (str)(int) = The index or char(s) to insert at.
        occurrence (int) = Valid only when 'at' is given as a string.
                    Specify which occurrence to insert at. default: first
        before (bool) = Valid only when 'at' is given as a string.
                    Specify inserting before or after. default: after
    :return:
        (str)
    '''
    try:
        return ''.join((src[:at], str(ins), src[at:]))

    except TypeError:
        i = src.replace(at, ' '*len(at), occurrence-1).find(at)
        return insert(src, str(ins), i if before else i+len(at)) if i!=-1 else src

#insert '88' before the second occurrence of 'bar'
print (insert('foo bar bar bar', 88, 'bar', 2, before=True))
#result:  "foo bar 88bar bar"

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM