【问题标题】:Get the string that is the midpoint between two other strings获取作为其他两个字符串之间中点的字符串
【发布时间】:2013-05-25 17:17:26
【问题描述】:

是否有可用的库或代码 sn-p 可以接受两个字符串并返回两个字符串之间的确切或近似中点字符串?

最好使用 Python 编写代码。

背景:

从表面上看,这似乎是一个简单的问题,但我有点挣扎:

  • 显然,“A”和“C”之间的中点字符串将是“B”。
  • 使用 base64 编码,“A”和“B”之间的中点字符串可能是“Ag”
  • 使用 UTF-8 编码,我不确定有效的中点是什么,因为中间字符似乎是控制字符:U+0088 c2 88 <control>

实际应用:

我问的原因是因为我希望编写 map-reduce 类型的算法来读取我们数据库中的所有条目并处理它们。数据库中的主键是 UTF-8 编码的字符串,字符随机分布。我们使用的数据库是 Cassandra。

希望从数据库中获取最低键和最高键,然后通过找到中点将其分成两个范围,然后通过找到它们的每个中点将这两个范围分成两个较小的部分,直到我有几千个部分,然后我可以异步读取每个部分。

字符串是否为 base-16 编码的示例:(一些中点是近似值):

开始最高和最低键:'000''FFF' / \ / \ '000' '8' '8' 'FFF' / \ / \ / \ / \ 结果:'000' '4' '4' '8' '8' 'B8' 'B8' 'FFF' (经过3级递归)

【问题讨论】:

标签: python string string-math


【解决方案1】:

不幸的是,not all sequences of bytes 是有效的 UTF-8,因此仅取 UTF-8 值的中点并非易事,如下所示。

def midpoint(s, e):
    '''Midpoint of start and end strings'''
    (sb, eb) = (int.from_bytes(bytes(x, 'utf-8'), byteorder='big') for x in (s, e))
    midpoint = int((eb - sb) / 2 + sb)

    midpoint_bytes = midpoint.to_bytes((midpoint.bit_length() // 8) + 1, byteorder='big')
    return midpoint_bytes.decode('utf-8')

基本上,这段代码将每个字符串转换为由内存中字节序列表示的整数,找到这两个整数的中点,并尝试再次将“中点”字节解释为 UTF-8。

根据您想要的具体行为,下一步可能是用某种替换字符替换 midpoint_bytes 中的无效字节,以形成有效的 UTF-8 字符串。对于您的问题,只要您保持一致,您使用哪个字符来替换可能并不重要。

但是,由于您正在尝试对数据进行分区并且似乎不太关心中点的字符串表示,另一种选择是将中点表示保留为整数并将键转换为整数,同时做分区。根据您问题的规模,此选项可能可行,也可能不可行。

【讨论】:

    【解决方案2】:

    这是一个通用解决方案,它给出了任意两个 Unicode 字符串 ab 之间的近似中点 m,如果可能的话,a < m < b

    from os.path import commonprefix
    
    # This should be set according to the range and frequency of
    # characters used.
    MIDCHAR = u'm'
    
    
    def midpoint(a, b):
        prefix = commonprefix((a, b))
        p = len(prefix)
        # Find the codepoints at the position where the strings differ.
        ca = ord(a[p]) if len(a) > p else None
        cb = ord(b[p])
        # Find the approximate middle code point.
        cm = (cb // 2 if ca is None else (ca + cb) // 2)
        # If a middle code point was found, add it and return.
        if ca < cm < cb:
            return prefix + unichr(cm)
        # If b still has more characters after this, then just use
        # b's code point and return.
        if len(b) > p + 1:
            return prefix + unichr(cb)
        # Otherwise, if cb == 0, then a and b are consecutive so there
        # is no midpoint. Return a.
        if cb == 0:
            return a
        # Otherwise, use part of a and an extra character so that
        # the result is greater than a.
        i = p + 1
        while i < len(a) and a[i] >= MIDCHAR:
            i += 1
        return a[:i] + MIDCHAR
    

    该函数假定a &lt; b。除此之外,它应该适用于任意 Unicode 字符串,甚至是包含 u'\x00' 字符的字符串。另请注意,它可能返回包含u'\x00' 或其他非标准代码点的字符串。如果由于b == a + u'\x00' 而没有中点,则返回a

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-28
      相关资源
      最近更新 更多