【问题标题】:Extract specific letters from text using regex and compare with dictionary使用正则表达式从文本中提取特定字母并与字典进行比较
【发布时间】:2018-07-12 18:28:32
【问题描述】:

我有一个 90% 格式为 AABBB-CCCDDD001 的文本列表。此列表中也有少数文本可能包含

AABBBICS-CCCDDD001 or 
AABBBIGW-CCCDDD001 or 
AABBBRTL-CCCDDD001 or 
AABBBTDZ-CCCDDD001

这些是设备的名称

AA - country code
BBB - site code
CCC - Function code
DDD - Sub Function code.

例如:USNYCRTL-LANDCE001

如果代码 ICS、IGW、RTL 或 TDZ 与文本中的代码匹配,我希望它输出它们各自的数字,为此我创建了一个字典:

ENVIRONMENTCODE = {
    'ICS': '1',
    'IGW': '2',
    'RTL': '3',
    'TDZ': '4'
}

NULLCODE = {
    'NULL': '9'
}

所以,如果文本是:

AABBBICS-CCCDDD001 it should print '1' or 
AABBBIGW-CCCDDD001 it should print '2' or 
AABBBRTL-CCCDDD001 it should print '3' or 
AABBBTDZ-CCCDDD001 it should print '4'

以上示例:USNYCRTL-LANDCE001 应打印“3”,因为 RTL 对应于字典中的数字“3”

现在,对于格式为 AABBB-CCCDDD001 的 90% 的文本,应该打印“9”,因为它应该与键“NULL”配对。此外,可能很少有文本可以包含 AABBBXYZ-CCCDDD001,但我们需要忽略该 XYZ,因为它不在字典中,只考虑字典中的那些。并将该文本也标记为“9”。

我知道可以在这里使用正则表达式,但我正处于学习 python 的早期阶段,而正则表达式似乎对我来说遥不可及。这是我迄今为止尝试过的:

def environmentcode(self):
    idx = self.name.find('-')
    if idx > -1:
        if self.name in ENVIRONMENTCODE:
            return ENVIRONMENTCODE
        else:
            return NULLCODE
    else:
        return "Not Found"

它只打印 NULLCODE 字典,无论文本中是否存在键。谁能帮我解决这个问题。

【问题讨论】:

    标签: python regex python-3.x


    【解决方案1】:

    我们可以使用.find获取码字,如果存在的话,然后使用字典将码字映射到它的码号。我们可以使用字典.get 方法返回缺失或未知码字的空码。如果遇到错误数据,此版本将返回 None:名称不包含 '-',或者名称在 '-' 之前没有 8 个或 5 个字母。

    env_code = {
        'ICS': '1',
        'IGW': '2',
        'RTL': '3',
        'TDZ': '4',
    }
    
    null_code = '9'
    
    def get_env_code(name):
        idx = name.find('-')
        if idx == 8:
            # code may be valid
            code = name[idx-3:idx]
        elif idx == 5:
            # code is missing
            code = ''
        else:
            # Bad name
            return None
    
        return env_code.get(code, null_code)
    
    # test
    
    data = [
        'AABBBICS-CCCDDD001',
        'AABBBIGW-CCCDDD001',
        'AABBBRTL-CCCDDD001',
        'AABBBTDZ-CCCDDD001',
        'USNYCRTL-LANDCE001',
        'AABBBXYZ-CCCDDD001',
        'AABBB-CCCDDD001',
        'BADDATA',
    ]
    
    for s in data:
        print(s, get_env_code(s))
    

    输出

    AABBBICS-CCCDDD001 1
    AABBBIGW-CCCDDD001 2
    AABBBRTL-CCCDDD001 3
    AABBBTDZ-CCCDDD001 4
    USNYCRTL-LANDCE001 3
    AABBBXYZ-CCCDDD001 9
    AABBB-CCCDDD001 9
    BADDATA None
    

    这是一个更简单的版本,它返回空代码而不是 None 用于错误数据。

    def get_env_code(name):
        idx = name.find('-')
        code = name[idx-3:idx] if idx == 8 else ''
        return env_code.get(code, null_code)
    

    【讨论】:

    • 这是完美的答案。我认为这是我的错误,我忘了提到这些代码在文本中的特定位置可能是小写或大写。例如,它可能是 aabbbics-cccddd001 或 AABBBICS-CCCDDD001,我尝试使用小写“ics”处理示例文本,但它无法读取该文本并在那里提取代码“9”。
    • ^ 我添加了小写代码。例如,env_code 字典中的 'ics'、'igw'、'rtl'、'tdz' 工作正常。你有其他方法吗?
    • @KaranM 将小写代码添加到字典中很好。它不使用更多的 RAM,而且速度很快。如果小写代码与大写版本具有相同的数字,例如,您希望 'ics' 和 'ICS' 都映射到 '1',那么还有另一种选择:您可以只使用大写代码字典并做env_code.get(code.upper(), null_code)。但这实际上要慢一些,因为它必须为每个代码调用.upper()
    • 好的,我已将这些小写代码添加到我的字典中,一切正常!顺便说一句,我今天已经完成了我的整个代码,令人难以置信的 170 多行脚本。这对于刚刚使用 Python 2 个月大的人来说是非常令人震惊但又令人着迷的。如果你愿意,我们是否应该研究它并尝试优化代码,因为我觉得这会增加很多 RAM。我已经在尝试了,但如果我有导师陪伴我会非常高兴,因为我正在尽我最大的努力。
    • @KaranM 要求优化完整工作程序的问题通常不在 Stack Overflow 上。它们在Code Review 上是可以接受的,尽管它们在那里有严格的规定,所以你需要在发帖前仔细阅读这些规定。但是,通过专注于您认为可以加速或使用更少 RAM 的程序的单个部分,可以获得一些优化 SO 的帮助。所以你需要为那个部分创建一个minimal reproducible example,解释它的作用,以及为什么你认为它可以改进。
    【解决方案2】:

    如果您只是检查是否在每个测试字符串中找到ENVIRONMENTCODE 的成员,则不需要正则表达式。你可以只使用python关键字in,例如

    ENVIRONMENTCODE = {
        'ICS': '1',
        'IGW': '2',
        'RTL': '3',
        'TDZ': '4'
    }
    
    NULLCODE = {
        'NULL': '9'
    }
    
    def environment_code(test_string, code_dict):
        if '-' not in test_string:
            return 'no dash'
        for code, value in code_dict.items():
            if code in test_string:
                return value
        return NULLCODE['NULL']
    
    
    to_test = ['AABBBICS-CCCDDD001',
               'AABBBIGW-CCCDDD001',
               'AABBBRTL-CCCDDD001',
               'AABBBTDZ-CCCDDD001']
    for test_str in to_test:
        print(environment_code(test_str, ENVIRONMENTCODE))
    

    您的原始代码的问题在于您尝试这样做

    test_string in code_dict

    它只检查被测字符串和字典中的键之间的完全匹配。

    【讨论】:

    • 文中有很多设备名称为ICS、IGW、RTL或TDZ。我将无法在那里创建 to_test 字典。我只需要匹配那些位置的 3 个特定字母,如果匹配则打印出它们各自的数字代码。明白了吗?
    • @KaranM 在这种情况下,您的AABBBICS-CCCDDD001 等样本数据有点误导。也许您应该添加更多字符串来向我们展示数据的真实样子。
    • to_test 列表仅作为示例。您应该只在您拥有的每个设备名称上调用上面的函数 environment_code()
    【解决方案3】:

    我的建议:

    def environmentcode(s):
        if "-" not in s:  #(**)
            return None   #(**)
        h,t=s.split("-")
        code=h.strip()[5:]
        return ENVIRONMENTCODE.get(code,9)   
    
    data="AABBBICS-CCCDDD001 AABBBIGW-CCCDDD001 AABBBRTL-CCCDDD001 AABBBTDZ-CCCDDD001 USNYCRTL-LANDCE001 AABBB-CCCDDD001 something"
    
    for s in data.split():
        print(s,"-->",environmentcode(s))
    
    Output:
    AABBBICS-CCCDDD001 --> 1
    AABBBIGW-CCCDDD001 --> 2
    AABBBRTL-CCCDDD001 --> 3
    AABBBTDZ-CCCDDD001 --> 4
    USNYCRTL-LANDCE001 --> 3
    AABBB-CCCDDD001 --> 9
    something --> None
    
    #---------------------------------------------------------
    # Filtering text with regex. In this case, (**) not needed.
    text="""AABBBICS-CCCDDD001 Alice was beginning to get very tired of sitting by her sister on the bank... AABBBIGW-CCCDDD001 AABBBRTL-CCCDDD001 AABBBTDZ-CCCDDD001 USNYCRTL-LANDCE001 AABBB-CCCDDD001 AABBBXYZ-CCCDDD001 something"""
    
    import re
    
    data= re.findall(r"\b[A-Z]{5,8}-[A-Z]{6}001\b",text)
    for s in data:
        print(s,"-->",environmentcode(s))
    

    【讨论】:

    • 这是我上面显示的格式,在这些文本中可能有任何字符,位于“ICS”、“IGW”、“RTL”、“TDZ”之间。我们只需要在文本中的特定位置检查这些代码。如果在该位置没有任何文本,或者在该位置有其他代码,则返回 NULL 代码,即数字 9
    猜你喜欢
    • 1970-01-01
    • 2019-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-10
    • 1970-01-01
    • 2014-12-14
    • 1970-01-01
    相关资源
    最近更新 更多