【问题标题】:Insert some string into given string at given index在给定索引处将一些字符串插入给定字符串
【发布时间】:2011-04-30 16:27:06
【问题描述】:

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

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

line = "Name Age Group Class Profession"

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

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

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

【问题讨论】:

    标签: python string


    【解决方案1】:
    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-strings 代替串联来节省一些额外的 CPU 周期(例如,f'{source_str[:pos]}{insert_str}{source_str[pos:]}' )。
    【解决方案2】:

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

    一种方法是使用切片:

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

    【讨论】:

      【解决方案3】:

      一个经常困扰新 Python 程序员但其他发帖者没有明确指出的重要一点是 Python 中的字符串是不可变的——您不能永远就地修改它们。

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

      【讨论】:

      • 这并不能真正成为 Python 没有索引插入或替换的借口!输出可能只是一个包含所需结果的新字符串。
      • @CodieCodeMonkey Python Zen 提到“显式优于隐式”。您希望开发人员知道他将处理副本。否则,他肯定会遇到对象身份问题,这将使调试感到沮丧。思考字符串 - 思考功能。
      • @Zakum,我明白你的意思,但这有先例,例如str.strip()。没有仔细阅读文档的开发者可能会认为 strip() 是在原始文档上运行的。
      • 这回答了没有一行代码的问题。正确心态的力量。
      • "how can I create a new string that has some pieces from this one I've already gotten?" 好的,但是如何
      【解决方案4】:

      为了让未来的“新手”解决这个问题,我认为这个帖子适合快速回答。

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

      【讨论】:

      • 很好的答案,但我相信电影标题拼写为“Kung Fu Panda”
      • 其实“spelled”和“spelt”都是正确的。 “拼写”是英国的拼写。 “Spelt”在美国是不可接受的,因为“muh,'farming'。”它因方言而异,“spelt”与“spelled”一样古老。例如,是“提出问题”还是“提出问题”?答案是两者——现在都快两千岁了,我相信在这两者中,“斧头”首先出现; “问”更受欢迎。
      • 请注意find() 将返回第一次出现的起始索引,如果未找到搜索字符串,它将返回-1。因此,这不会推广到感兴趣的字符串(在本例中为 Panda)可能多次出现或根本不出现的情况。
      【解决方案5】:

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

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

      【讨论】:

      • 这有什么不妥
      • @sehe 使用字符串拼接,效率不高
      • 谢谢,我希望您在答案中添加说明。不是每个人都能理解它的缺点,人们知道它很有用:)
      • @RobSmallshire 什么是更有效的方法?
      • @JacobJones 使用 str 的 join 方法可能会更有效,可能会避免较大的中间结果。 return ''.join((source_str[:pos], insert_str, source_str[pos:]))
      【解决方案6】:

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

      【讨论】:

      • 我不建议将变量命名为int,因为它会影响内置方法。当您稍后尝试使用 int("5") 之类的内容时,这可能会导致较大的程序出现问题。
      【解决方案7】:

      实施

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

      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
      

      【讨论】:

        【解决方案8】:

        Insert characters of string in other string al located positions的答案

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

        【讨论】:

        猜你喜欢
        • 2011-05-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-14
        • 2017-11-12
        • 2020-05-16
        • 1970-01-01
        相关资源
        最近更新 更多