【问题标题】:Python locate specific words without duplicatesPython 定位不重复的特定单词
【发布时间】:2020-11-06 13:46:29
【问题描述】:

我有问题。我正在尝试在字符串中查找设备名称。我要查找的所有设备名称都存储在一个列表中。我想要的有一件非常重要的事情:

  • 一个命令可以有多个设备!!!

现在我遇到的问题是:

我有两个设备(FanFan Light)。当我发出命令时:Turn on Fan Light 两个设备都已找到,但我只想找到 Fan Light。我尝试检查所有已找到的设备并将最长的设备设置为找到的设备,如下所示:

# Create 2 dummy devices
device1 = {
    "name": "fan"
}

device2 = {
    "name": "fan light"
}


# Add devices to list
devices = []
devices.append(device1)
devices.append(device2)


# Given command
command = "Turn on fan light"
    
    
foundDevices = []

# Search devices in sentence
for device in devices:

    # Splits a device name if it has multiple words
    deviceSplit = device["name"].split()
    numOfSubNames = len(deviceSplit)

    # Checks for every sub-name if it is found in the string
    i = 0
    for subName in deviceSplit:
        if subName in command:
            i += 1

    # Checks if all names where located in string
    if i == numOfSubNames:
         foundDevices.append(device["name"])

# Checks if multiple devices have been found
if len(foundDevices) >= 2:
    largestNameLength = 0

    # Checks which device has the largest name
    for device in foundDevices:
        if (len(device) > largestNameLength):
            largestName = device
            largestNameLength = len(device)


    # Clears list and only add longest one
    foundDevices.clear()
    foundDevices.append(largestName)


print(foundDevices)

但是当我说例如“打开风扇灯和风扇”时会出现问题,因为该命令确实包含多个设备。 如何以我想要的方式扫描设备?

【问题讨论】:

  • 这个和实体识别有关,如果你不想那样的话,我建议你在粉丝词之后提供命令,比如fan runfan stop
  • 那么"turn on the Fan Light, and also the fan"(不同大小写)的结果是什么?
  • 或者您可以识别所有匹配的位置,例如使用find 并丢弃子匹配,即包含在更大匹配中的设备。
  • 结果:"Turn on the Fan Light and the Fan" 应该是:["Fan Light", "Fan"]

标签: python


【解决方案1】:

正则表达式搜索是一种快速执行所需操作的方法,其模式由不同的设备名称组成。

import re

def find_with_regex(command, pattern):
    return list(set(re.findall(pattern, command, re.IGNORECASE)))

我还建议构建device: name 形状的逆向字典,也许它有助于快速找到给定设备的代号。

devices = [{'name': 'fan light'}, {'name': 'fan'}]

# build a quick-reference dict with device>name structure
transformed = {dev: name for x in devices for name, dev in x.items()}
# should also help weeding out duplicated devices
# as it would raise an error as soon as it fids one

# print(transformed)
# {'fan light': 'name', 'fan': 'name'}

特别感谢 buddemat 指出设备名称按特定顺序排列以使该解决方案能够正常工作,并在下一个代码块的模式制作行中使用 reversed(sorted(... 对其进行了修复。

测试功能

test_cases = [
    'Turn on fan light',
    'Turn on fan light and fan',
    'Turn on fan and fan light',
    'Turn on fan and fan',
]

pattern = '|'.join(reversed(sorted(transformed)))
for command in test_cases:
    matches = find_with_regex(command, pattern)
    print(matches)

输出

['fan light']
['fan', 'fan light']
['fan', 'fan light']
['fan']

【讨论】:

  • 如果你不需要IGNORECASE标志,你可以去掉它
【解决方案2】:

如果您不想依靠对设备列表进行排序来确保正确的结果,您可以使用 python regex 模块而不是 re 模块(以改进 RichieV 的好答案)。

re 的问题在于,它不符合 POSIX,因此管道运算符 | 不会确保返回 最长的最左边 匹配项(另请参阅 How to order regular expression alternatives to get longest match? )。

但是,在 regex 中,您可以在正则表达式模式之前指定 (?p) 以确保 POSIX 匹配。

一共

import regex

devices = [{'name': 'fan'}, {'name': 'fan light'}]

test_cases = [
    'Turn on fan light',
    'Turn on fan light and fan',
    'Turn on fan and fan light',
    'Turn on fan and fan',
]

transformed = {dev: name for x in devices for name, dev in x.items()}

pattern = '|'.join(transformed)

for command in test_cases:
    matches = regex.findall(r'(?p)'+pattern,command)
    print(matches)

会给你

['fan light']
['fan light', 'fan']
['fan', 'fan light']
['fan', 'fan']

无论devices中的字典顺序如何。

【讨论】:

    猜你喜欢
    • 2019-10-16
    • 2019-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-05
    • 2020-05-25
    • 2018-07-27
    • 1970-01-01
    相关资源
    最近更新 更多