【发布时间】:2021-12-13 14:57:46
【问题描述】:
我正在尝试制作一个模糊的自动完成建议框,以突出显示带有 HTML 标记的搜索字符
例如,如果用户输入“ldi”并且其中一个建议是“Leonardo DiCaprio”,那么期望的结果是“Leonardo D我卡普里奥”。每个字符的第一次出现按出现顺序突出显示。
我现在正在做的是:
def prototype_finding_chars_in_string():
test_string_list = ["Leonardo DiCaprio", "Brad Pitt","Claire Danes","Tobey Maguire"]
comp_string = "ldi" #chars to highlight
regex = ".*?" + ".*?".join([f"({x})" for x in comp_string]) + ".*?" #results in .*?(l).*?(d).*?(i).*
regex_compiled = re.compile(regex, re.IGNORECASE)
for x in test_string_list:
re_search_result = re.search(regex_compiled, x) # correctly filters the test list to include only entries that features the search chars in order
if re_search_result:
print(f"char combination {comp_string} are in {x} result group: {re_search_result.groups()}")
结果
char combination ldi are in Leonardo DiCaprio result group: ('L', 'D', 'i')
现在我想用<b>[whatever in the result]</b> 替换结果组中的每个匹配项,但我不知道该怎么做。
我目前正在做的是循环遍历结果并使用内置的str.replace 方法来替换出现的情况:
def replace_with_bold(result_groups, original_string):
output_string: str = original_string
for result in result_groups:
output_string = output_string.replace(result,f"<b>{result}</b>",1)
return output_string
这会导致:
Highlighted string: <b>L</b>eonar<b>d</b>o D<b>i</b>Caprio
但我认为,当我已经拥有匹配组时,像这样在结果上循环是浪费的。此外,它甚至不正确,因为它从每个循环的开头检查字符串。所以对于输入 'ooo',结果如下:
char combination ooo are in Leonardo DiCaprio result group: ('o', 'o', 'o')
Highlighted string: Le<b><b><b>o</b></b></b>nardo DiCaprio
什么时候应该是Le<b>o</b>nard<b>o</b> DiCapri<b>o</b>
有没有办法简化这个?也许这里的正则表达式有点矫枉过正?
【问题讨论】:
-
将您的模式从
.*?(l).*?(d).*?(i).*更改为(l)(.*?)(d)(.*?)(i)并使用捕获组内容构建您的替换。 (注意,只有奇数捕获需要包含在 b 标签之间) -
您能详细说明一下吗?你的意思是像
f"<b>{group_1}</b>{group_2}<b>{group_2}</b>{group_3}"这样的东西吗?这听起来是个好主意。但是不会省略第一个.*?产生仅以 'l' 开头的结果吗? -
省略第一个
.*?应该没有问题,re.sub和re.search不会像re.match那样锚定到字符串的开头。 -
@CasimiretHippolyte 但是第一场比赛之前的文本会发生什么?如果我理解正确,您是说我应该一个接一个地组合结果组。但是第一次匹配之前的文本不在结果中。还是我错过了什么?
-
想法是根据组的数量动态构建替换字符串(或您喜欢的格式化字符串)。