如何从重复的字符串中提取单词
Posted
技术标签:
【中文标题】如何从重复的字符串中提取单词【英文标题】:How to extract words from repeating strings 【发布时间】:2021-09-23 22:40:53 【问题描述】:这里我有一个列表中的字符串:
['aaaaaaappppppprrrrrriiiiiilll']
我想在列表中获取单词“april”,但不只是其中一个,而是单词“april”实际出现在字符串中的次数。
输出应该是这样的:
['aprilaprilapril']
因为 'april' 这个词在那个字符串中出现了 3 次。
这个词实际上并没有出现三次,所有字符都出现了。所以我想将这些字符排序为“四月”,它们在字符串中出现了多少次。
我的想法基本上是从一些随机字符串中提取单词,但不仅仅是提取单词,而是提取字符串中出现的所有单词。应该提取每个单词,并且应该按照我想要的方式对单词(字符)进行排序。
但是在这里我有一些烦人的情况;你不能删除列表中的所有元素,然后用单词'april'替换它们(你不能用单词'april'替换整个字符串);您只能从字符串中提取“四月”,而不是替换它们。您也不能删除带有字符串的列表。想想所有的字符串都有非常重要的数据,我们只想要一些数据,但是这些数据必须是有序的,我们需要删除所有与我们的“数据链”不匹配的数据(单词'april') .但是一旦删除整个字符串,您将丢失所有重要数据。您不知道如何制作另一条“数据链”,因此我们不能只将“四月”一词放回列表中。
如果有人知道如何解决我的奇怪问题,请帮助我,我是一个初学者 python 程序员。谢谢!
【问题讨论】:
【参考方案1】:一个单词只会出现最少字母重复次数的次数。考虑到单词中出现重复字母的可能性(例如,appril
,您需要考虑这个计数。这是使用collections.Counter
执行此操作的一种方法:
from collections import Counter
def count_recurrence(kernel, string):
# we need to count both strings
kernel_counter = Counter(kernel)
string_counter = Counter(string)
# now get effective count by dividing the occurence in string by occurrence
# in kernel
effective_counter =
k: int(string_counter.get(k, 0)/v)
for k, v in kernel_counter.items()
# min occurence of kernel is min of effective counter
min_recurring_count = min(effective_counter.values())
return kernel * min_recurring_count
【讨论】:
【参考方案2】:使用正则表达式怎么样?
import re
word = 'april'
text = 'aaaaaaappppppprrrrrriiiiiilll'
regex = "".join(f"(c+)" for c in word)
match = re.match(regex, text)
if match:
# Find the lowest amount of character repeats
lowest_amount = min(len(g) for g in match.groups())
print(word * lowest_amount)
else:
print("no match")
输出:
aprilaprilapril
像魅力一样工作
【讨论】:
【参考方案3】:这是一种更原生的方法,具有简单的迭代。
时间复杂度为 O(n)。
它使用外部循环遍历搜索键中的字符,然后使用内部 while 循环消耗搜索字符串中该字符的所有出现,同时维护一个计数器。一旦当前字母的所有连续出现都被消耗,它会将minLetterCount
更新为其先前值或此新计数的最小值。一旦我们遍历了键中的所有字母,我们就会返回这个累积的最小值。
def countCompleteSequenceOccurences(searchString, key):
left = 0
minLetterCount = 0
letterCount = 0
for i, searchChar in enumerate(key):
while left < len(searchString) and searchString[left] == searchChar:
letterCount += 1
left += 1
minLetterCount = letterCount if i == 0 else min(minLetterCount, letterCount)
letterCount = 0
return minLetterCount
测试:
testCasesToOracles =
"aaaaaaappppppprrrrrriiiiiilll": 3,
"ppppppprrrrrriiiiiilll": 0,
"aaaaaaappppppprrrrrriiiiii": 0,
"aaaaaaapppppppzzzrrrrrriiiiiilll": 0,
"pppppppaaaaaaarrrrrriiiiiilll": 0,
"zaaaaaaappppppprrrrrriiiiiilll": 3,
"zzzaaaaaaappppppprrrrrriiiiiilll": 3,
"aaaaaaappppppprrrrrriiiiiilllzzz": 3,
"zzzaaaaaaappppppprrrrrriiiiiilllzzz": 3,
key = "april"
for case, oracle in testCasesToOracles.items():
result = countCompleteSequenceOccurences(case, key)
assert result == oracle
用法:
key = "april"
result = countCompleteSequenceOccurences("aaaaaaappppppprrrrrriiiiiilll", key)
print(result * key)
输出:
aprilaprilapril
【讨论】:
【参考方案4】:一种方法是使用itertools.groupby
,它将单独对字符进行分组,然后使用zip
解包和迭代它们,这将迭代n次给定n是最小组中的字符数(即具有最少字符数的组)字符)
from itertools import groupby
'aaaaaaappppppprrrrrriiiiiilll'
result = ''
for each in zip(*[list(g) for k, g in groupby('aaaaaaappppppprrrrrriiiiiilll')]):
result += ''.join(each)
# result = 'aprilaprilapril'
另一种可能的解决方案是创建一个自定义计数器来计算每个唯一的字符序列(请注意,此方法仅适用于 Python 3.6+,对于较低版本的 Python,不保证字典顺序):
def getCounts(strng):
if not strng:
return [], 0
counts =
current = strng[0]
for c in strng:
if c in counts.keys():
if current==c:
counts[c] += 1
else:
current = c
counts[c] = 1
return counts.keys(), min(counts.values())
result = ''
counts=getCounts('aaaaaaappppppprrrrrriiiiiilll')
for i in range(counts[1]):
result += ''.join(counts[0])
# result = 'aprilaprilapril'
【讨论】:
以上是关于如何从重复的字符串中提取单词的主要内容,如果未能解决你的问题,请参考以下文章