替换字符串

时间:2016-01-29 18:31:20

标签: python string replace substring

我想替换字符串中第n个子串的出现。

必须有一些与我想做的事情相同的东西

mystring.replace("substring", 2nd)

实现这一目标的最简单,最恐怖的方式是什么?

为什么不重复:我不想在这种方法中使用正则表达式,我发现的类似问题的大多数答案只是正则表达式剥离或真正复杂的功能。我真的希望尽可能简单而不是正则表达式解决方案。

13 个答案:

答案 0 :(得分:15)

您可以使用带有str.find的while循环来查找第n个匹配项(如果它存在)并使用该位置创建新字符串:

def nth_repl(s, sub, repl, nth):
    find = s.find(sub)
    # if find is not p1 we have found at least one match for the substring
    i = find != -1
    # loop util we find the nth or we find no match
    while find != -1 and i != nth:
        # find + 1 means we start at the last match start index + 1
        find = s.find(sub, find + 1)
        i += 1
    # if i  is equal to nth we found nth matches so replace
    if i == nth:
        return s[:find]+repl+s[find + len(sub):]
    return s

示例:

In [14]: s = "foobarfoofoobarbar"

In [15]: nth_repl(s, "bar","replaced",3)
Out[15]: 'foobarfoofoobarreplaced'

In [16]: nth_repl(s, "foo","replaced",3)
Out[16]: 'foobarfooreplacedbarbar'

In [17]: nth_repl(s, "foo","replaced",5)
Out[17]: 'foobarfoofoobarbar'

答案 1 :(得分:3)

我使用简单函数,它列出所有出现次数,选择第n个位置并使用它将原始字符串拆分为两个子字符串。然后它替换第二个子字符串中的第一个匹配项,并将子字符串连接回新字符串:

import re

def replacenth(string, sub, wanted, n)
    where = [m.start() for m in re.finditer(sub, string)][n-1]
    before = string[:where]
    after = string[where:]
    after = after.replace(sub, wanted, 1)
    newString = before + after
    print newString

对于这些变量:

string = 'ababababababababab'
sub = 'ab'
wanted = 'CD'
n = 5

输出:

ababababCDabababab

注意:

  

where变量实际上是匹配位置的列表,您可以从中获取第n个位置。但是列表项索引通常以0开头,而不是1。因此,有一个n-1索引,n变量是实际的第n个子字符串。我的例子找到第5个字符串如果您使用n索引并希望找到第5个位置,则n需要4。你使用的通常取决于函数,它生成我们的n

     

这应该是最简单的方法,但也许它不是最Pythonic方式,因为where变量构造需要导入re库。也许有人会发现更多的Pythonic方式。

     

来源和一些链接:

     

答案 2 :(得分:2)

我已经提出了下面的内容,它还考虑了将所有“旧”字符串出现在左侧或右侧的选项。当然,没有选择来替换所有出现的事件,因为标准的str.replace是完美的。

def nth_replace(string, old, new, n=1, option='only nth'):
    """
    This function replaces occurrences of string 'old' with string 'new'.
    There are three types of replacement of string 'old':
    1) 'only nth' replaces only nth occurrence (default).
    2) 'all left' replaces nth occurrence and all occurrences to the left.
    3) 'all right' replaces nth occurrence and all occurrences to the right.
    """
    if option == 'only nth':
        left_join = old
        right_join = old
    elif option == 'all left':
        left_join = new
        right_join = old
    elif option == 'all right':
        left_join = old
        right_join = new
    else:
        print("Invalid option. Please choose from: 'only nth' (default), 'all left' or 'all right'")
        return None
    groups = string.split(old)
    nth_split = [left_join.join(groups[:n]), right_join.join(groups[n:])]
    return new.join(nth_split)

答案 3 :(得分:1)

最后一个答案几近完美 - 只有一次更正:

    def replacenth(string, sub, wanted, n):
        where = [m.start() for m in re.finditer(sub, string)][n - 1]
        before = string[:where]
        after = string[where:]
        after = after.replace(sub, wanted)
        newString = before + after
        return newString

替换后,必须再次将after-string存储在this变量中。 谢谢你们的出色解决方案!

答案 4 :(得分:1)

聚会有点晚了,但我认为这种方式非常pythonian(据我所知)并且它不需要for循环或计数器

def Nreplacer(string,srch,rplc,n):
    Sstring = string.split(srch)
    #first check if substring is even present n times
    #then paste the part before the nth substring to the part after the nth substring
    #, with the replacement inbetween
    if len(Sstring) > (n):
        return f'{srch.join(Sstring[:(n)])}{rplc}{srch.join(Sstring[n:])}' 
    else:
        return string

答案 5 :(得分:0)

我有类似的需求,即在日志中找到IP并有选择地仅替换src IP或dst IP字段。这就是我用pythonic方式实现的方式;

import re

mystr = '203.23.48.0 DENIED 302 449 800 1.1 302 http d.flashresultats.fr  10.111.103.202 GET GET - 188.92.40.78 '
src = '1.1.1.1'
replace_nth = lambda mystr, pattern, sub, n: re.sub(re.findall(pattern, mystr)[n - 1], sub, mystr)
result = replace_nth(mystr, '\S*\d+\.\d+\.\d+\.\d+\S*', src, 2)
print(result)

答案 6 :(得分:0)

def replace_nth_occurance(some_str, original, replacement, n):
    """ Replace nth occurance of a string with another string
    """
    some_str.replace(original, replacement, n)
    for i in range(n):
        some_str.replace(replacement, original, i)
    return some_str

答案 7 :(得分:0)

一般解决方案:用另一个字符串替换子字符串[pattern]的任何指定实例。

def replace(instring,pattern,replacement,n=[1]):
  """Replace specified instance(s) of pattern in string.

  Positional arguments
    instring - input string
     pattern - regular expression pattern to search for
 replacement - replacement

  Keyword arguments
           n - list of instances requested to be replaced [default [1]]

"""
  import re
  outstring=''
  i=0
  for j,m in enumerate(re.finditer(pattern,instring)):
    if j+1 in n: outstring+=instring[i:m.start()]+replacement
    else: outstring+=instring[i:m.end()]
    i=m.end()
  outstring+=instring[i:]
  return outstring

答案 8 :(得分:0)

我的两分钱

a='01ab12ab23ab34ab45ab56ab67ab78ab89ab90';print('The original string: ', a)
sTar = 'ab';print('Look for: ', sTar)
n = 4; print('At occurence #:', n)
sSub = '***';print('Substitute with: ', sSub)

t = 0
for i in range(n):
   t = a.find(sTar,t)
   print(i+1, 'x occurence at', t)
   if t != -1: t+=1

t-=1   #reset, get the correct location
yy = a[:t] + a[t:].replace(sTar, sSub, 1)
print('New string is:', yy)

输出

The original string:  01ab12ab23ab34ab45ab56ab67ab78ab89ab90
Look for:  ab
At occurence #: 4
Substitute with:  ***
1 x occurence at 2
2 x occurence at 6
3 x occurence at 10
4 x occurence at 14
New string is: 01ab12ab23ab34***45ab56ab67ab78ab89ab90

答案 9 :(得分:0)

优雅而简短:

def replace_ocurrance(string,from,to,num)
     strange_char = “$&$@$$&”
     return string.replace(from,strange_char,num).replace(strange_char, from,num-1).replace(to, strange_char,1)

答案 10 :(得分:0)

只有几个非正则表达式的答案,我想提供我自己的解决方案,我认为它更简单、更容易理解。创建一个新字符串并计算要替换的字符的第 n 次出现次数。

def replace_nth_occurence(old_str, old_char, new_char, n):
    new_str = ""
    occurences = 0
    for s in old_str:
        if s == old_char:
            occurences += 1
            if occurences == n:
                new_str += new_char # append the new character instead of the old
            else:
                new_str += s
        else:
            new_str += s
    return new_str

replace_nth_occurence("Testing_One_Two_Three", "_", "?", 3)
>> Testing_One_Two?Three

答案 11 :(得分:0)

可能是最短且最简单的解决方案之一,无需任何外部库。

def replace_nth(sub,repl,txt,nth):
    arr=txt.split(sub)
    part1=sub.join(arr[:nth])
    part2=sub.join(arr[nth:])
    
    return part1+repl+part2

我做了几次测试,效果很好。

答案 12 :(得分:0)

@Padraic Cunningham 的答案中有一个简单的错误,即出现次数 n 仅比允许的值大 1 (n = maximum_occurances + 1)。

所以这是他的代码的更正版本:

def nth_repl(s, old, new, n):
find = s.find(old)
# If find is not -1 we have found at least one match for the substring
i = find != -1
# loop until we find the nth or we find no match
while find != -1 and i != n:
    # find + 1 means we start searching from after the last match
    find = s.find(old, find + 1)
    i += 1
# If i is equal to n we found nth match so replace
if i == n and i <= len(s.split(old))-1:
    return s[:find] + new + s[find+len(old):]
return s