【问题标题】:Ignoring case, punctuation, and whitespace in Strings忽略字符串中的大小写、标点和空格
【发布时间】:2010-01-30 19:41:36
【问题描述】:

在字符串中忽略大小写、标点和空格的最有效方法是什么?这些字符串应该被分成单词而不是字符应该忽略前面提到的比较细节,这些单词字符串的切片应该尽可能高效并考虑到速度。

我打算对以下代码使用不区分大小写和标点符号的字符串,但在看到评估 class Slice: def __eq__(self, other): return self.root == other.root 需要多长时间后,我决定改用 data = tuple(string.split())。对于已经在下面的代码中表达的计算量大的算法来说,让字符串不区分大小写、标点符号和间距并且处理单词而不是字符的代价太高了。

class Slice:

    def __init__(self, data, offset, length):
        self.prefix = data[:offset]
        self.root = data[offset:offset+length]
        self.suffix = data[offset+length:]

    def __eq__(self, other):
        return self.root == other.root

    def __len__(self):
        return len(self.root)

################################################################################

class Match:

    def __init__(self, data, key, prefix_tree, suffix_tree):
        self.data = data
        self.key = key
        self.prefix_tree = prefix_tree
        self.suffix_tree = suffix_tree
        self.__value = len(key) + prefix_tree.value() + suffix_tree.value()

    def value(self):
        return self.__value

################################################################################

class Tree(tuple):

    def __new__(cls, nodes):
        tree = super().__new__(cls, nodes)
        tree.__value = max(map(Match.value, tree)) if tree else 0
        return tree

    def value(self):
        return self.__value

    def find(self, value):
        for index, match in enumerate(self):
            if match.value() == value:
                return index
        raise ValueError()

################################################################################

def search(data, key):
    length = 0
    nodes = []
    for d_block in shrink(data, len(key)):
        block_len = len(d_block)
        if length > block_len:
            return Tree(nodes)
        for k_block in slide(key, block_len):
            if d_block == k_block:
                length = block_len
                prefix_tree = search(d_block.prefix, k_block.prefix)
                suffix_tree = search(d_block.suffix, k_block.suffix)
                match = Match(d_block, k_block, prefix_tree, suffix_tree)
                nodes.append(match)
    return Tree(nodes)

def shrink(data, max_len):
    for length in range(min(len(data), max_len), 0, -1):
        for block in slide(data, length):
            yield block

def slide(data, length):
    for offset in range(len(data) - length + 1):
        yield Slice(data, offset, length)

################################################################################

def build_tree(nodes):
    match = nodes[nodes.find(nodes.value())]
    node = match.key
    if match.prefix_tree:
        node.prefix = build_tree(match.prefix_tree)
    if match.suffix_tree:
        node.suffix = build_tree(match.suffix_tree)
    return node

def flatten_tree(node):
    array = [0]
    _flatten(node, array)
    return tuple(array)

def _flatten(node, array):
    if isinstance(node.prefix, Slice):
        _flatten(node.prefix, array)
    else:
        array.append(node.prefix)
    array[0] += 1
    array.append((array[0], node.root))
    if isinstance(node.suffix, Slice):
        _flatten(node.suffix, array)
    else:
        array.append(node.suffix)

【问题讨论】:

  • 如果有一些关于该类的用途的上下文/文档会有所帮助......
  • 请不要使用__ 作为您的“私有”变量名。请使用_:这更常见,并且阅读您的代码时我们的大脑压力较小。
  • 我有点困惑;问题是什么?

标签: python filter state slice


【解决方案1】:

“解决此问题的最佳方法是什么?”

最好的——也是唯一的——方法是定义这个对象“意味着”什么以及这个对象的长度“意味着”什么。

该对象似乎是一个单词列表。而已。这似乎是_string 中的值。

不清楚_simple 是什么,除了_string 中不可访问的过滤子集。

那么长度是多少?是词长还是过滤后的子集中词长?

只有您可以定义此类含义含义将决定如何实现__len__。在定义含义之前,不可能确定应该如何实现任何东西。

【讨论】:

    【解决方案2】:

    如果您希望对 String 实例进行迭代以在其 self.__string 上进行迭代,正如您的 __iter__ 方法所表明的那样,长度的唯一明智选择也是返回 __string 的长度——它将是 真正如果len(x)sum(1 for _ in x) 产生不同的值,则很奇怪。

    我不得不承认我不明白这个类的目的(尤其是为什么你做出了旧式的可怕选择,以及为什么你使用这种扭曲的方式来构建__simple),但是无论如何,内部一致性很重要。所以,要么改变__iter__,要么让__len__在逻辑上兼容它。

    你的切片逻辑也完全让我无法理解——为什么你构建切片的__simple 的方式可能与你从切片的__string 重建它得到的不同?例如,如果 self.__string 是 '?Boh!'因此self.__simple 是'boh',你为什么想要 self[1:-1] 有一个'Boh' 的__string 但有一个'o' 的__simple,如此不兼容,不同,并且与 __simple 不一致,您可以通过从切片中重新计算得到它...?

    我想这与这个关于长度的问题无关,但我只是对你做出的许多极其奇特的设计选择感到好奇......

    【讨论】:

    • 自从 Python 3.0 出现以来,我一直只使用该语言(目前是 3.1)编写代码。如果你熟悉 3.1 中的类是如何工作的,那么你就知道这是一个新式类(Python 3.x 中的所有类都是新式类)。因此,没有必要显式地从object 继承。至于切片是如何工作的,请注意这一行:self.__string = tuple(string.split()) 这些字符串对象作用于单词而不是字符。
    • @Noctis,您对代码进行了如此彻底的更改(例如,我再也看不到 String 类了!)以至于无法将我的 cmets 重新连接到您当前的代码。至于 Python 3,这很好,但在 Q 中提及它显然会更好,因为这不是当今绝大多数 Python 用户正在使用的;-)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-08-23
    • 2016-11-11
    • 1970-01-01
    • 1970-01-01
    • 2016-01-29
    • 1970-01-01
    • 2010-09-08
    相关资源
    最近更新 更多