Python 检查列表项是否(不)包含任何其他列表项

Python Check if list item does (not) contain any of other list items

我遇到这个问题,我想删除包含 'illegal' 个字符的列表元素。合法字符在多个列表中指定。它们是这样形成的,其中 alpha 代表字母表 (a-z + A-Z),digit 代表数字 (0-9),punct 代表标点符号。

alpha = list(string.ascii_letters)
digit = list(string.digits)
punct = list(string.punctuation)

这样我就可以将未出现在这些列表之一中的某些内容指定为非法字符。

之后我有一个包含元素的列表:

Input = ["Amuu2", "Q1BFt", "dUM€n", "o°8o1G", "mgF)`", "ZR°p", "Y9^^M", "W0PD7"]

我想过滤掉包含非法字符的元素。所以这是我想要得到的结果(不需要排序):

var = ["Amuu2", "Q1BFt", "mgF)`", "Y9^^M", "W0PD7"]

编辑:

我已经尝试过(以及它的所有变体):

for InItem in Input:
    if any(AlItem in InItem for AlItem in alpha+digit+punct):
        FilInput.append(InItem)

创建的新列表仅包含过滤后的元素,但这里的问题是,当元素至少包含一个合法字符时,元素就会被添加。例如:添加了 "ZR°p",因为它包含一个 Z、R 和一个 p。

我也试过:

for InItem in Input:
    if not any(AlItem in InItem for AlItem in alpha+digit+punct):

但在那之后,我不知道如何删除该元素。 哦,还有一个小技巧,为了让它变得更加困难,如果速度快一点就好了,因为它需要完成数百万次。但它需要先工作。

您可以使用列表理解并检查 all 是否所有字符都符合您的条件:

>>> [element for element in Input if all(c in alpha + digit + punct for c in element)]
['Amuu2', 'Q1BFt', 'mgF)`', 'Y9^^M', 'W0PD7']

定义一组合法字符。然后应用列表理解。

>>> allowed = set(string.ascii_letters + string.digits + string.punctuation)
>>> inp = ["Amuu2", "Q1BFt", "dUM€n", "o°8o1G", "mgF)`", "ZR°p", "Y9^^M", "W0PD7"]
>>> [x for x in inp if all(c in allowed for c in x)]
['Amuu2', 'Q1BFt', 'mgF)`', 'Y9^^M', 'W0PD7']

您的代码

正如您提到的,只要 any 个字符正确,您就可以添加单词。您需要检查它们是否 all 正确:

filtered_words = []
for word in words:
    if all(char in alpha+digit+punct for char in word):
        filtered_words.append(word)

print(filtered_words)
# ['Amuu2', 'Q1BFt', 'mgF)`', 'Y9^^M', 'W0PD7']

您还可以检查没有一个字符不正确:

filtered_words = []
for word in words:
    if not any(char not in alpha+digit+punct for char in word):
        filtered_words.append(word)

print(filtered_words)

虽然可读性差很多。

为了提高效率,您不应在每次迭代期间将列表与 alpha+digit+punct 连接起来。你应该在任何循环之前一劳永逸地做。从这些列表中创建一个集合也是一个好主意,因为当有很多允许的字符时,char in setchar in list 快得多。

最后,您可以使用列表理解来避免 for 循环。如果你做了所有这些,你最终会得到 :)

用正则表达式替代

您可以从您的列表中创建一个正则表达式模式并查看哪些词匹配:

# encoding: utf-8
import string
import re

alpha = list(string.ascii_letters)
digit = list(string.digits)
punct = list(string.punctuation)

words = ["Amuu2", "Q1BFt", "dUM€n", "o°8o1G", "mgF)`", "ZR°p", "Y9^^M", "W0PD7"]

allowed_pattern = re.compile(
    '^[' +
    ''.join(
        re.escape(char) for char in (
            alpha +
            digit +
            punct)) +
    ']+$')
# ^[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\!\"\#$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\]\^_\`\{\|\}\~]+$

print([word for word in words if allowed_pattern.match(word)])
# ['Amuu2', 'Q1BFt', 'mgF)`', 'Y9^^M', 'W0PD7']

你也可以这样写:

print(list(filter(allowed_pattern.match, words)))
# ['Amuu2', 'Q1BFt', 'mgF)`', 'Y9^^M', 'W0PD7']

re.compile 可能比简单地初始化 set 需要更多时间,但过滤可能会更快。

这是针对您的问题的 "not" 有效解决方案,但对于学习如何循环列表、字符等可能会很有趣。

# coding=utf-8
import string

# Aux var
result =[]
new_elem = ""

# lists with legal characters
alpha = list(string.ascii_letters)
digit = list(string.digits)
punct = list(string.punctuation)

# Input strings
Input = ["Amuu2", "Q1BFt", "dUM€n", "o°8o1G", "mgF)`", "ZR°p", "Y9^^M", "W0PD7"]

# Loop all elements of the list and each char of them
for elem in Input:
    ## check each char 
    for char in elem:
        if char in alpha:
            #print 'is ascii'
            new_elem += char
        elif char in digit:
            #print 'is digit'
            new_elem += char
        elif char in punct:
            #print 'is punct'
            new_elem += char
        else:
            new_elem = ""
            break
    ## Add to result list
    if new_elem != "":
        result.append(new_elem)
        new_elem = ""

print result