按单词拆分(不区分大小写)

Split by a word (case insensitive)

如果我想带

"hi, my name is foo bar"

并在 "foo" 上拆分,并让该拆分不区分大小写(在 "foO""FOO""Foo" 等中的任何一个上拆分),应该我愿意?请记住,虽然我希望拆分不区分大小写,但我也确实希望保持字符串其余部分的大小写敏感。

所以如果我有:

test = "hi, my name is foo bar"

print test.split('foo')

print test.upper().split("FOO")

我会得到

['hi, my name is ', ' bar']
['HI, MY NAME IS ', ' BAR']

分别。

但我想要的是:

['hi, my name is ', ' bar']

每一次。目标是保持原始字符串的大小写敏感性,除了我要拆分的内容。

所以如果我的测试字符串是:

"hI MY NAME iS FoO bar"

我想要的结果是:

['hI MY NAME iS ', ' bar']

您可以使用re.split function with the re.IGNORECASE flag(或简称re.I):

>>> import re
>>> test = "hI MY NAME iS FoO bar"
>>> re.split("foo", test, flags=re.IGNORECASE)
['hI MY NAME iS ', ' bar']
>>>

您还可以搜索一些东西并获取关键字的起始位置。我会推荐并用 "substring" 方法将其删除。 (我来自 C#,所以我不知道这种语言的方法是什么)

这不是确切答案,而是基于问题的解决方案。 在网上搜索了一段时间后,我实现了以下内容。

这是我的自定义标签(参见 how to do it)。

from django.template.defaultfilters import register
from django.utils.html import escape
from django.utils.safestring import mark_safe

@register.simple_tag
def highlight(string, entry, prefix, suffix):
    string = escape(string)
    entry = escape(entry)
    string_upper = string.upper()
    entry_upper = entry.upper()
    result = ''
    length = len(entry)
    start = 0
    pos = string_upper.find(entry_upper, start)
    while pos >= 0:
        result += string[start:pos]
        start = pos + length
        result += prefix + string[pos:start] + suffix
        pos = string_upper.find(entry_upper, start)
    result += string[start:len(string)]
    return mark_safe(result)

它接受不安全的字符串和 returns 转义结果。

这样使用:

<span class="entityCode">{% highlight entity.code search_text '<span class="highlighted">' '</span>' %}</span>

我使用嵌套<span>来继承所有的样式。它显示类似

一个非常不合理的解决方案,当你想精确地分割一次时(奖励:它也保留了找到的分隔符的大小写,所以你知道你实际分割的是什么):

teststr = "hI MY NAME iS FoO bar"
blen, _, alen = map(len, teststr.casefold().partition("foo"))
before, sep, after = teststr[:blen], teststr[blen:-alen], teststr[-alen:]
print([before, sep, after])

哪个输出(包括字符串的原始分隔符,如果你愿意可以丢弃):

['hI MY NAME iS ', 'FoO', ' bar']

Try it online!

类似的代码可以用 teststr.casefold().index("foo") 加上基于索引和分隔符长度的切片来编写;我喜欢 partition 为我做更多的工作(无论分隔符是否出现在字符串中,都可以无分支地工作),但这纯粹是个人喜好。

这可以适应拆分任意次数(但丢失分隔符,因为 str.split 丢弃它们,不像 str.partition)与 itertools 助手:

from itertools import accumulate, pairwise  # On 3.10+, pairwise is a built-in, pre-3.10, you'd use the pairwise recipe from itertools docs
                                            # accumulate only accepts an initial argument
                                            # on 3.8+, but you can fake it with chain before that

teststr = "hI MY NAME iS FoO bar aNd I LOvE fOoD!"
components = [teststr[s+i*3:e+i*3] 
              for i, (s, e) in enumerate(pairwise(accumulate(map(len, teststr.casefold().split("foo")), initial=0)))]
print(components)

产生:

['hI MY NAME iS ', ' bar aNd I LOvE ', 'D!']

Try it online!

说清楚,第一种方案不合理,第二种方案很疯狂。我post这主要是为了说明;在这种情况下 non-regex 解决方案是疯狂的,所以即使你同意我的观点,应该尽可能避免使用正则表达式,但在这种情况下还是硬着头皮使用它们。