簡體   English   中英

Python:如何替換文本中出現的N個隨機字符串?

[英]Python: How to replace N random string occurrences in text?

假設我有 10 個不同的標記,“(TOKEN)”在一個字符串中。 如何用其他字符串替換隨機選擇的其中 2 個標記,同時保持其他標記完好無損?

>>> import random
>>> text = '(TOKEN)__(TOKEN)__(TOKEN)__(TOKEN)__(TOKEN)__(TOKEN)__(TOKEN)__(TOKEN)__(TOKEN)__(TOKEN)'
>>> token = '(TOKEN)'
>>> replace = 'foo'
>>> num_replacements = 2
>>> num_tokens = text.count(token) #10 in this case
>>> points = [0] + sorted(random.sample(range(1,num_tokens+1),num_replacements)) + [num_tokens+1]
>>> replace.join(token.join(text.split(token)[i:j]) for i,j in zip(points,points[1:]))
'(TOKEN)__(TOKEN)__(TOKEN)__(TOKEN)__foo__(TOKEN)__foo__(TOKEN)__(TOKEN)__(TOKEN)'

在 function 表格中:

>>> def random_replace(text, token, replace, num_replacements):
        num_tokens = text.count(token)
        points = [0] + sorted(random.sample(range(1,num_tokens+1),num_replacements)) + [num_tokens+1]
        return replace.join(token.join(text.split(token)[i:j]) for i,j in zip(points,points[1:]))

>>> random_replace('....(TOKEN)....(TOKEN)....(TOKEN)....(TOKEN)....(TOKEN)....(TOKEN)....(TOKEN)....(TOKEN)....','(TOKEN)','FOO',2)
'....FOO....(TOKEN)....(TOKEN)....(TOKEN)....(TOKEN)....(TOKEN)....(TOKEN)....FOO....'

測試:

>>> for i in range(0,9):
        print random_replace('....(0)....(0)....(0)....(0)....(0)....(0)....(0)....(0)....','(0)','(%d)'%i,i)


....(0)....(0)....(0)....(0)....(0)....(0)....(0)....(0)....
....(0)....(0)....(0)....(0)....(1)....(0)....(0)....(0)....
....(0)....(0)....(0)....(0)....(0)....(2)....(2)....(0)....
....(3)....(0)....(0)....(3)....(0)....(3)....(0)....(0)....
....(4)....(4)....(0)....(0)....(4)....(4)....(0)....(0)....
....(0)....(5)....(5)....(5)....(5)....(0)....(0)....(5)....
....(6)....(6)....(6)....(0)....(6)....(0)....(6)....(6)....
....(7)....(7)....(7)....(7)....(7)....(7)....(0)....(7)....
....(8)....(8)....(8)....(8)....(8)....(8)....(8)....(8)....

如果你正好需要兩個,那么:

  1. 檢測標記(保留一些指向它們的鏈接,比如字符串中的索引)
  2. 隨機選擇兩個( random.choice
  3. 替換它們

你究竟想做什么? 一個好的答案將取決於...

也就是說,想到的一個蠻力解決方案是:

  1. 將 10 個標記存儲在一個數組中,這樣 tokens[0] 是第一個標記,tokens[1] 是第二個,...等等
  2. 創建一個字典將每個唯一的“(TOKEN)”與兩個數字相關聯:start_idx,end_idx
  3. 編寫一個小解析器遍歷您的字符串並查找 10 個標記中的每一個。 每當找到一個時,在該標記出現的字符串中記錄開始/結束索引(如 start_idx、end_idx)。
  4. 完成解析后,生成范圍 [0,9] 中的隨機數。 讓我們稱之為R
  5. 現在,你的隨機“(TOKEN)”是 tokens[ R ];
  6. 使用步驟(3)中的字典查找字符串中的start_idx、end_idx值; 用“其他字符串”替換那里的文本

我的代碼解決方案:

import random

s = "(TOKEN)test(TOKEN)fgsfds(TOKEN)qwerty(TOKEN)42(TOKEN)(TOKEN)ttt"
replace_from = "(TOKEN)"
replace_to = "[REPLACED]"
amount_to_replace = 2

def random_replace(s, replace_from, replace_to, amount_to_replace):
    parts = s.split(replace_from)
    indices = random.sample(xrange(len(parts) - 1), amount_to_replace)

    replaced_s_parts = list()

    for i in xrange(len(parts)):
        replaced_s_parts.append(parts[i])
        if i < len(parts) - 1:
            if i in indices:
                replaced_s_parts.append(replace_to)
            else:
                replaced_s_parts.append(replace_from)

    return "".join(replaced_s_parts)

#TEST

for i in xrange(5):
    print random_replace(s, replace_from, replace_to, 2)

解釋:

  1. 使用replace_from將字符串分成幾個部分
  2. 使用random.sample選擇要替換的標記索引。 此返回列表包含唯一編號
  3. 構建一個字符串重建列表,用replace_to生成的索引替換標記。
  4. 將所有列表元素連接成單個字符串

試試這個解決方案:

import random

def replace_random(tokens, eqv, n):
    random_tokens = eqv.keys()
    random.shuffle(random_tokens)
    for i in xrange(n):
        t = random_tokens[i]
        tokens = tokens.replace(t, eqv[t])
    return tokens

假設存在帶有標記的字符串,並且可以通過替換每個標記來構造合適的等價表:

tokens = '(TOKEN1) (TOKEN2) (TOKEN3) (TOKEN4) (TOKEN5) (TOKEN6) (TOKEN7) (TOKEN8) (TOKEN9) (TOKEN10)'

equivalences = {
    '(TOKEN1)' : 'REPLACEMENT1',
    '(TOKEN2)' : 'REPLACEMENT2',
    '(TOKEN3)' : 'REPLACEMENT3',
    '(TOKEN4)' : 'REPLACEMENT4',
    '(TOKEN5)' : 'REPLACEMENT5',
    '(TOKEN6)' : 'REPLACEMENT6',
    '(TOKEN7)' : 'REPLACEMENT7',
    '(TOKEN8)' : 'REPLACEMENT8',
    '(TOKEN9)' : 'REPLACEMENT9',
    '(TOKEN10)' : 'REPLACEMENT10'
}

你可以這樣稱呼它:

replace_random(tokens, equivalences, 2)
> '(TOKEN1) REPLACEMENT2 (TOKEN3) (TOKEN4) (TOKEN5) (TOKEN6) (TOKEN7) (TOKEN8) REPLACEMENT9 (TOKEN10)'

有很多方法可以做到這一點。 我的方法是編寫一個 function,它采用原始字符串、令牌字符串和一個 function,它返回原始字符串中出現的令牌的替換文本:

def strByReplacingTokensUsingFunction(original, token, function):
    outputComponents = []
    matchNumber = 0
    unexaminedOffset = 0
    while True:
        matchOffset = original.find(token, unexaminedOffset)
        if matchOffset < 0:
            matchOffset = len(original)
        outputComponents.append(original[unexaminedOffset:matchOffset])
        if matchOffset == len(original):
            break
        unexaminedOffset = matchOffset + len(token)
        replacement = function(original=original, offset=matchOffset, matchNumber=matchNumber, token=token)
        outputComponents.append(replacement)
        matchNumber += 1
    return ''.join(outputComponents)

(您當然可以將其更改為使用更短的標識符。我的風格比典型的 Python 風格更冗長。)

鑒於 function,很容易替換十分之二的隨機出現。 這是一些示例輸入:

sampleInput = 'a(TOKEN)b(TOKEN)c(TOKEN)d(TOKEN)e(TOKEN)f(TOKEN)g(TOKEN)h(TOKEN)i(TOKEN)j(TOKEN)k'

random 模塊有一個方便的方法來從總體中隨機選擇項目(不是兩次選擇相同的項目):

import random
replacementIndexes = random.sample(range(10), 2)

然后我們可以使用上面的 function 來替換隨機選擇的事件:

sampleOutput = strByReplacingTokensUsingFunction(sampleInput, '(TOKEN)',
    (lambda matchNumber, token, **keywords:
        'REPLACEMENT' if (matchNumber in replacementIndexes) else token))
print sampleOutput

這是一些測試 output:

a(TOKEN)b(TOKEN)cREPLACEMENTd(TOKEN)e(TOKEN)fREPLACEMENTg(TOKEN)h(TOKEN)i(TOKEN)j(TOKEN)k

這是另一個運行:

a(TOKEN)bREPLACEMENTc(TOKEN)d(TOKEN)e(TOKEN)f(TOKEN)gREPLACEMENTh(TOKEN)i(TOKEN)j(TOKEN)k
from random import sample

mystr = 'adad(TOKEN)hgfh(TOKEN)hjgjh(TOKEN)kjhk(TOKEN)jkhjk(TOKEN)utuy(TOKEN)tyuu(TOKEN)tyuy(TOKEN)tyuy(TOKEN)tyuy(TOKEN)'

def replace(mystr, substr, n_repl, replacement='XXXXXXX', tokens=10, index=0):
    choices = sorted(sample(xrange(tokens),n_repl))
    for i in xrange(choices[-1]+1):
        index = mystr.index(substr, index) + 1
        if i in choices:
            mystr = mystr[:index-1] + mystr[index-1:].replace(substr,replacement,1)
    return mystr

print replace(mystr,'(TOKEN)',2)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM