Python正则表达式与字符串匹配的问题

标签 python regex python-3.x fuzzy-search fuzzy-logic

提前抱歉这么长的帖子

编辑--

修改自诺曼的解决方案,如果我们找到精确的解决方案,则打印并返回,否则打印所有近似匹配。对于在下面第三个 Pastebin 链接上提供的字典文件中搜索 etnse 的特定示例,目前仍仅获得 83/85 匹配。

def doMatching(file, origPattern):
    entireFile = file.read()
    patterns = []
    startIndices = []

    begin = time.time()

    # get all of the patterns associated with the given phrase
    for pattern in generateFuzzyPatterns(origPattern):
        patterns.append(pattern)
        for m in re.finditer(pattern, entireFile):
            startIndices.append((m.start(), m.end(), m.group()))
        # if the first pattern(exact match) is valid, then just print the results and we're done
        if len(startIndices) != 0 and startIndices[0][2] == origPattern:
            print("\nThere is an exact match at: [{}:{}] for {}").format(*startIndices[0])
            return

    print('Used {} patterns:').format(len(patterns))
    for i, p in enumerate(patterns, 1):
        print('- [{}]  {}').format(i, p)

    # list for all non-overlapping starting indices
    nonOverlapping = []
    # hold the last matches ending position
    lastEnd = 0
    # find non-overlapping matches by comparing each matches starting index to the previous matches ending index
    # if the starting index > previous items ending index they aren't overlapping
    for start in sorted(startIndices):
        print(start)
        if start[0] >= lastEnd:
            # startIndicex[start][0] gets the ending index from the current matches tuple
            lastEnd = start[1]
            nonOverlapping.append(start)

    print()
    print('Found {} matches:').format(len(startIndices))
    # i is the key <starting index> assigned to the value of the indices (<ending index>, <string at those indices>
    for start in sorted(startIndices):
        # *startIndices[i] means to unpack the tuple associated to the key i's value to be used by format as 2 inputs
        # for explanation, see: http://stackoverflow.com/questions/2921847/what-does-the-star-operator-mean-in-python
        print('- [{}:{}]  {}').format(*start)

    print()
    print('Found {} non-overlapping matches:').format(len(nonOverlapping))
    for ov in nonOverlapping:
        print('- [{}:{}]  {}').format(*ov)

    end = time.time()
    print(end-begin)

def generateFuzzyPatterns(origPattern):
    # Escape individual symbols.
    origPattern = [re.escape(c) for c in origPattern]

    # Find exact matches.
    pattern = ''.join(origPattern)
    yield pattern

    # Find matches with changes. (replace)
    for i in range(len(origPattern)):
        t = origPattern[:]
        # replace with a wildcard for each index
        t[i] = '.'
        pattern = ''.join(t)
        yield pattern

    # Find matches with deletions. (omitted)
    for i in range(len(origPattern)):
        t = origPattern[:]
        # remove a char for each index
        t[i] = ''
        pattern = ''.join(t)
        yield pattern

    # Find matches with insertions.
    for i in range(len(origPattern) + 1):
        t = origPattern[:]
        # insert a wildcard between adjacent chars for each index
        t.insert(i, '.')
        pattern = ''.join(t)
        yield pattern

    # Find two adjacent characters being swapped.
    for i in range(len(origPattern) - 1):
        t = origPattern[:]
        if t[i] != t[i + 1]:
            t[i], t[i + 1] = t[i + 1], t[i]
            pattern = ''.join(t)
            yield pattern

原文: http://pastebin.com/bAXeYZcD - 实际功能

http://pastebin.com/YSfD00Ju - 要使用的数据,应该是 8 个“ware”匹配项,但只得到 6 个

http://pastebin.com/S9u50ig0 - 要使用的数据,应该为“etnse”获得 85 个匹配项,但只获得 77 个

我将所有原始代码留在了函数中,因为我不确定到底是什么导致了问题。

您可以在任何内容上搜索“Board:isFull()”以获得下面所述的错误。

示例:

假设您将第二个 Pastebin 命名为“someFile.txt”,该文件夹位于与 .py 文件相同的目录中名为 files 的文件夹中。

file = open('./files/someFile.txt', 'r')
doMatching(file, "ware")

或者

file = open('./files/someFile.txt', 'r')
doMatching(file, "Board:isFull()")

或者

假设您将第三个 Pastebin 命名为“dictionary.txt”,位于与 .py 文件同一目录中名为 files 的文件夹中。

file = open('./files/dictionary.txt', 'r')
doMatching(file, "etnse")

--编辑

函数参数的工作方式如下:

file 是文件的位置。

origPattern 是一个短语。

该功能基本上应该是模糊搜索。它应该采用模式并搜索文件以查找完全匹配或有 1 个字符偏差的匹配。即:1 个缺失字符、1 个额外字符、1 个替换字符或 1 个与相邻字符交换的字符。

在很大程度上它是有效的,但我遇到了一些问题。

首先,当我尝试对 origPattern 使用类似“Board:isFull()”的内容时,我得到以下结果:

    raise error, v # invalid expression
sre_constants.error: unbalanced parenthesis

以上内容来自re库

我尝试过使用 re.escape() 但它没有改变任何东西。

其次,当我尝试像“Fun()”这样的其他东西时,它说它在某个索引处有一个匹配项,而该索引甚至不包含任何一个;它只是一行“*”

第三,当它找到匹配项时,它并不总是找到所有匹配项。例如,我有一个文件应该找到 85 个匹配项,但它只找到了 77 个匹配项,另一个文件有 8 个匹配项,但它只找到了 6 个。但是,它们只是按字母顺序排列的,所以这可能只是我如何处理的问题进行搜索或其他操作。

感谢任何帮助。

我也无法使用fuzzyfinder

最佳答案

我在代码中发现了一些问题:

  1. re.escape() 似乎不起作用,因为它的结果未分配。
    执行origPattern = re.escape(origPattern)
  2. 当模式正确转义时,请注意在操作模式时不要破坏转义。
    示例:re.escape('Fun()') 生成字符串 Fun\(\)。其中的两个 \( 子字符串绝不能分开:切勿删除、替换或交换没有转义字符的 \
    不良操作:Fun(\)(删除)、Fu\n(\)(交换)、Fun\.{0,2}\).
    良好的操作:Fun\)(删除)、Fu\(n\)(交换)、Fun.{0,2}\) .
  3. 您找到的匹配项太少,因为如果没有精确匹配项,您只会尝试查找模糊匹配项。 (参见 ifindexs.__len__() != 0: 行。)您必须始终寻找它们。
  4. 插入 '.{0,2}' 的循环产生了过多的模式,例如'ware.{0,2}' 表示 ware。除非您有意这样做,否则此模式将找到有两个插入的 wareXY
  5. 带有 .{0,2} 的模式无法按照描述的方式工作;它们允许一次更改和一次插入。
  6. 我不确定涉及 difflib.Differ 的代码。我不明白,但我怀疑不应该有 break 语句。
  7. 即使您使用set来存储索引,来自不同正则表达式的匹配仍可能重叠。
  8. 您不在正则表达式中使用单词边界 (\b),尽管对于自然语言来说这是有意义的。
  9. 不是错误,而是:为什么要显式调用魔术方法?
    (例如 indices.__len__() != 0 而不是 len(indices) != 0。)

我稍微重写了您的代码以解决我看到的任何问题:

def doMatching(file, origPattern):
    entireFile = file.read()
    patterns = []
    startIndices = {}

    for pattern in generateFuzzyPatterns(origPattern):
        patterns.append(pattern)
        startIndices.update((m.start(), (m.end(), m.group())) for m in re.finditer(pattern, entireFile))

    print('Used {} patterns:'.format(len(patterns)))
    for i, p in enumerate(patterns, 1):
        print('- [{}]  {}'.format(i, p))

    nonOverlapping = []
    lastEnd = 0
    for start in sorted(startIndices):
        if start >= lastEnd:
            lastEnd = startIndices[start][0]
            nonOverlapping.append(start)

    print()
    print('Found {} matches:'.format(len(startIndices)))
    for i in sorted(startIndices):
        print('- [{}:{}]  {}'.format(i, *startIndices[i]))

    print()
    print('Found {} non-overlapping matches:'.format(len(nonOverlapping)))
    for i in nonOverlapping:
        print('- [{}:{}]  {}'.format(i, *startIndices[i]))


def generateFuzzyPatterns(origPattern):
    # Escape individual symbols.
    origPattern = [re.escape(c) for c in origPattern]

    # Find exact matches.
    pattern = ''.join(origPattern)
    yield pattern

    # Find matches with changes.
    for i in range(len(origPattern)):
        t = origPattern[:]
        t[i] = '.'
        pattern = ''.join(t)
        yield pattern

    # Find matches with deletions.
    for i in range(len(origPattern)):
        t = origPattern[:]
        t[i] = ''
        pattern = ''.join(t)
        yield pattern

    # Find matches with insertions.
    for i in range(len(origPattern) + 1):
        t = origPattern[:]
        t.insert(i, '.')
        pattern = ''.join(t)
        yield pattern

    # Find two adjacent characters being swapped.
    for i in range(len(origPattern) - 1):
        t = origPattern[:]
        if t[i] != t[i + 1]:
            t[i], t[i + 1] = t[i + 1], t[i]
            pattern = ''.join(t)
            yield pattern

关于Python正则表达式与字符串匹配的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36526497/

相关文章:

c# - 正则表达式,我需要改进一种从图像中获取 src 和 alt 的方法

python - 使用 Pandas 计算不同子段的 T 统计量

python - 检查 Web 对象是否在 Selenium 中的其他 Web 对象前面?

python - 对行和下一行执行某些操作,直到击中符号为止

python - 如何从 Java 客户端向 Python FastAPI 服务器发出 JSON POST 请求?

javascript - 正则表达式: transferring the data attribute

python - 当有很多线程时,队列不会处理所有元素

python-3.x - 根据现有列中的值创建新列

python - 使用flask和python3的GET方法和较大的文本

python - 字典 : replacing key characters with whitespace