替换字符串中所有出现的内容,但替换第一个

时间:2018-11-10 14:29:41

标签: python regex

给出字符串:

  

X做了一些事。 X觉得很好,所以X回家了。

我想用Y替换所有出现的X,但第一个出现,用Y替换,使得输出字符串看起来像:

  

X做了一些事。 Y觉得很好,所以Y回家了。

我尝试了许多正则表达式模式(基于https://vi.stackexchange.com/questions/10905/substitution-how-to-ignore-the-nth-first-occurrences-of-a-pattern),但未能通过Python实现。

7 个答案:

答案 0 :(得分:7)

str.partition将字符串分为定界符之前的部分,定界符本身和之后的部分,如果不存在定界符,则将字符串和两个空字符串分开。归结为:

s = 'X did something. X found it to be good, and so X went home.'
before, first, after = s.partition('X')
result = before + first + after.replace('X', 'Y')

答案 1 :(得分:6)

您冷酷地使用re.sub使用函数的事实:

import re


def repl(match, count=[0]):
    x, = count
    count[0] += 1
    if x > 0:
        return 'Y'
    return 'X'


print(re.sub('X', repl, 'X did something. X found it to be good, and so X went home.'))

输出

X did something. Y found it to be good, and so Y went home.

想法是使用保留可见X计数的函数,然后在计数大于1时将其替换。

答案 2 :(得分:3)

另一种选择是找到第一个并且仅在替换所有X次出现之后。

最后,将句子的开头和开头连在一起

st = 'X did something. X found it to be good, and so X went home.'
first_found = st.find('X')
print (st[:first_found + 1] + st[first_found + 1:].replace('X', 'Y'))
# X did something. Y found it to be good, and so Y went home.

答案 3 :(得分:2)

这是没有正则表达式的低技术解决方案。 :)

>>> s = 'X did something. X found it to be good, and so X went home'
>>> s = s.replace('X', 'Y').replace('Y', 'X', 1)
>>> s
>>> 'X did something. Y found it to be good, and so Y went home'

原始字符串中是否存在'Y'的解决方案:

def replace_tail(s, target, replacement):
    try:
        pos = s.index(target)
    except ValueError:
        return s
    pos += len(target)
    head = s[:pos]
    tail = s[pos:]
    return head + tail.replace(target, replacement)

演示:

>>> s = 'Today YYY and XXX did something. XXX found it to be good, and so XXX went home without YYY.'
>>> replace_tail(s, 'XXX', 'YYY')
>>> 'Today YYY and XXX did something. YYY found it to be good, and so YYY went home without YYY.'

答案 4 :(得分:1)

在找到其余字符串的第一个匹配项之后,迭代地应用正则表达式。或者,如果可能,仅使用replace

答案 5 :(得分:1)

我们可以使用 slicing 生成两个字符串:第一个字符串(直到(包括)第一个元素),以及下一个包含其余元素的切片。然后,我们可以在该部分上应用替换部分,并将它们合并回去:

def replace_but_first(text, search, replace):
    try:
        idx = text.index(search) + len(search)
        return text[:idx] + text[idx:].replace(search, replace)
    except ValueError:  # we did not found a single match
        return text

例如:

>>> replace_but_first('X did something. X found it to be good, and so X went home.', 'X', 'Y')
'X did something. Y found it to be good, and so Y went home.'

答案 6 :(得分:0)

如果您仍然对使用正则表达式操作感兴趣,可以使用re.finditer()。这将返回一个迭代器,该迭代器将为找到的每个匹配案例生成$this->widget('zii.widgets.jui.CJuiDatePicker',array( 'name'=>'date_from', 'id' => 'date_from', //'value'=> date('d/m/Y',strtotime($date_from)), 'options'=>array( 'dateFormat' =>'dd/mm/yy', 'altFormat' =>'dd/mm/yy', 'changeMonth' => true, 'changeYear' => true, 'showAnim'=>'slide', 'showButtonPanel'=>true, ), 'language' => 'en-GB', 'htmlOptions'=>array( 'class'=>'form-control' ), )); 个实例。通过将迭代器转换为列表,可以索引到MatchObject实例中。在下面的函数中,MatchObject表示跳过第一场比赛。

[1:]

运行:

def replace_rest(my_string, replacement):

    for match in list(re.finditer(r'(X)', my_string))[1:]:
        my_string = my_string[0:match.start()] + replacement + my_string[match.end():]

    return my_string

输出:

>>> my_string = "Person X did something. X found it to be good, and so Y went home."

旁注:这对于忽略模式的第n个出现也很有用。