首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Python -使用HTML将出现在另一个字符串中的给定列表中的字符串实例包围起来

Python -使用HTML将出现在另一个字符串中的给定列表中的字符串实例包围起来
EN

Stack Overflow用户
提问于 2017-06-19 23:45:56
回答 1查看 99关注 0票数 3

我已经编写了一个函数,它用一个具有给定属性的HTML元素来包围一个搜索词。其思想是将产生的包围字符串稍后写入日志文件,并突出显示搜索词。

代码语言:javascript
复制
def inject_html(needle, haystack, html_element="span", html_attrs={"class":"matched"}):
    # Find all occurrences of a given string in some text
    # Surround the occurrences with a HTML element and given HTML attributes
    new_str = haystack
    start_index = 0
    while True:
        try:
            # Get the bounds
            start = new_str.lower().index(needle.lower(), start_index)
            end = start + len(needle)

            # Needle is present, compose the HTML to inject
            html_open = "<" + html_element + " " + " ".join(["%s=\"%s\""%(k,html_attrs[k]) for k in html_attrs]) + ">"
            html_close = "</" + html_element + ">"

            new_str = new_str[0:start] + html_open + new_str[start:end] + html_close + new_str[end:len(new_str)]
            start_index = end + len(html_close) + len(html_open)

        except ValueError as ex:
            # String doesn't occur in text after index, break loop
            break
    return new_str

我想打开它,接受一组针,在干草堆中用HTML定位和包围它们。我可以很容易地做到这一点,通过使用另一个循环来包围代码,该循环遍历针,定位和包围搜索词的实例。问题是,这并不能防止意外地包围以前注入的HTML代码。

代码语言:javascript
复制
def inject_html(needles, haystack, html_element="span", html_attrs={"class":"matched"}):
    # Find all occurrences of a given string in some text
    # Surround the occurrences with a HTML element and given HTML attributes
    new_str = haystack
    for needle in needles:
        start_index = 0
        while True:
        try:
            # Get the bounds
            start = new_str.lower().index(needle.lower(), start_index)
            end = start + len(needle)

            # Needle is present, compose the HTML to inject
            html_open = "<" + html_element + " " + " ".join(["%s=\"%s\""%(k,html_attrs[k]) for k in html_attrs]) + ">"
            html_close = "</" + html_element + ">"

            new_str = new_str[0:start] + html_open + new_str[start:end] + html_close + new_str[end:len(new_str)]
            start_index = end + len(html_close) + len(html_open)

        except ValueError as ex:
            # String doesn't occur in text after index, break loop
            break
    return new_str

search_strings = ["foo", "pan", "test"]
haystack = "Foobar"
print(inject_html(search_strings,haystack))

<s<span class="matched">pan</span> class="matched">Foo</span>bar

在第二次迭代中,代码搜索并包围上一次迭代中插入的"span“中的”span“文本。

您如何建议我将原来的函数更改为查找针的列表,而不会有将HTML注入到不需要的位置(例如在现有标记内)的风险。

更新--

我通过维护一个“免疫”范围的列表来解决这个问题(那些已经被HTML包围的区域,因此不需要再次检查。

代码语言:javascript
复制
def inject_html(needles, haystack, html_element="span", html_attrs={"class":"matched"}):
    # Find all occurrences of a given string in some text
    # Surround the occurrences with a HTML element and given HTML attributes
    immune = []
    new_str = haystack
    for needle in needles:
        next_index = 0
        while True:
            try:
                # Get the bounds
                start = new_str.lower().index(needle.lower(), next_index)
                end = start + len(needle)

                if not any([(x[0] > start and x[0] < end) or (x[1] > start and x[1] < end) for x in immune]):
                    # Needle is present, compose the HTML to inject
                    html_open = "<" + html_element + " " + " ".join(["%s=\"%s\""%(k,html_attrs[k]) for k in html_attrs]) + ">"
                    html_close = "</" + html_element + ">"

                    new_str = new_str[0:start] + html_open + new_str[start:end] + html_close + new_str[end:len(new_str)]
                    next_index = end + len(html_close) + len(html_open)

                    # Add the highlighted range (and HTML code) to the list of immune ranges
                    immune.append([start, next_index])

            except ValueError as ex:
                # String doesn't occur in text after index, break loop
                break

    return new_str

虽然这不是特别的Pythonic式的,但我很有兴趣看看是否有人能想出一些更干净的东西。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-08-09 04:27:16

我会使用类似这样的东西:

代码语言:javascript
复制
def inject_html(phrases, text_body, html_element_name="span", html_attrs={"class":"matched"}):

    new_text_body = []

    html_start_tag = "<" + html_element_name + " ".join(["%s=\"%s\""%(k,html_attrs[k]) for k in html_attrs]) + ">"
    html_end_tag = "</" + html_element_name + ">"

    text_body_lines = text_body.split("\n")

    for line in text_body_lines:
        for p in phrases:
            if line.lower() == p.lower():
                line = html_start_tag + p + html_end_tag
                break

        new_text_body.append(line)

    return "\n".join(new_text_body)

它逐行遍历并替换每一行,如果该行完全匹配(不区分大小写)。

第二轮:

由于要求匹配需要(1)不区分大小写,(2)匹配每行上的多个单词/短语,我将使用:

代码语言:javascript
复制
import re

def inject_html(phrases, text_body, html_element_name="span", html_attrs={"class": "matched"}):

    html_start_tag = "<" + html_element_name + " " + " ".join(["%s=\"%s\"" % (k, html_attrs[k]) for k in html_attrs]) + ">"
    html_end_tag = "</" + html_element_name + ">"

    for p in phrases:
        text_body = re.sub(r"({})".format(p), r"{}\1{}".format(html_start_tag, html_end_tag), text_body, flags=re.IGNORECASE)

    return text_body

对于每个提供的短语p,这将使用不区分大小写的re.sub()替换来替换所提供文本中该短语的所有实例。(p)通过正则表达式组匹配短语。\1是一个回填操作符,它匹配找到的短语,并将其包含在HTML标记中。

代码语言:javascript
复制
text = """
Somewhat more than forty years ago, Mr Baillie Fraser published a 
lively and instructive volume under the title _A Winter’s Journey  
(Tatar) from Constantinople to Teheran. Political complications 
had arisen between Russia and Turkey - an old story, of which we are 
witnessing a new version at the present time. The English government 
deemed it urgently necessary to send out instructions to our 
representatives at Constantinople and Teheran.
"""

new = inject_html(["TEHERAN", "Constantinople"], text)

print(new)

> Somewhat more than forty years ago, Mr Baillie Fraser published a lively and instructive volume under the title _A Winter’s Journey (Tatar) from <span class="matched">Constantinople</span> to <span class="matched">Teheran</span>. Political complications had arisen between Russia and Turkey - an old story, of which we are witnessing a new version at the present time. The English government deemed it urgently necessary to send out instructions to our representatives at <span class="matched">Constantinople</span> and <span class="matched">Teheran</span>.
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44634826

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档