使用RegEx与列表推导式提取日志值时的默认值设置问题
问题描述
我需要用正则表达式从日志中提取特定值,将结果存入列表后用于Pandas DataFrame。大部分情况运行正常,但当日志不包含目标值时,应该添加' - '来避免数组长度不一致导致DataFrame报错。
当日志包含目标值时,代码能得到预期输出:
import re attribute = "</System><EventData><Data Name='TargetUserName'>superuser</Data><Data Name='TargetDomainName'>ACME</Data>" username_list = [' - ' if ' '.join(re.findall("(?<=='TargetUserName'>).*?(?=</Data>)",attribute)) not in attribute else ' '.join(re.findall("(?<=='TargetUserName'>).*?(?=</Data>)",attribute))] print(username_list)
输出:
['superuser']
但当日志没有匹配结果时,得到的是空字符串列表,不符合预期:
attribute = "</System><EventData>superuser</EventData><Data Name='TargetDomainName'>ACME</Data>" username_list = [' - ' if ' '.join(re.findall("(?<=='TargetUserName'>).*?(?=</Data>)",attribute)) not in attribute else ' '.join(re.findall("(?<=='TargetUserName'>).*?(?=</Data>)",attribute))] print(username_list)
输出:
['']
预期输出:
[' - ']
请问代码哪里出错了?
错误原因
你的判断逻辑存在问题:当re.findall找不到匹配时,会返回空列表,' '.join(空列表)会得到空字符串''。而空字符串本身是任何字符串的子串,所以'' not in attribute永远为False,导致else分支执行,最终返回空字符串。
解决方案
直接判断re.findall的返回结果是否为空,而非用拼接后的字符串检查是否在原文本中。优化后的代码如下:
import re def extract_username(attribute): matches = re.findall("(?<=='TargetUserName'>).*?(?=</Data>)", attribute) # 无匹配则返回[' - '],否则返回拼接后的匹配结果 return [' - '] if not matches else [' '.join(matches)] # 测试有匹配的情况 attribute1 = "</System><EventData><Data Name='TargetUserName'>superuser</Data><Data Name='TargetDomainName'>ACME</Data>" print(extract_username(attribute1)) # 输出: ['superuser'] # 测试无匹配的情况 attribute2 = "</System><EventData>superuser</EventData><Data Name='TargetDomainName'>ACME</Data>" print(extract_username(attribute2)) # 输出: [' - ']
额外优化建议
- 用
re.search替代re.findall:日志中TargetUserName通常只会出现一次,直接取匹配结果更高效:
match = re.search(r"(?<=='TargetUserName'>)(.*?)(?=</Data>)", attribute) return [' - '] if not match else [match.group(1)]
- 优先用XML解析库处理这类日志:正则表达式处理XML格式存在局限性(比如标签嵌套、属性值引号变化等),用
xml.etree.ElementTree更可靠:
import xml.etree.ElementTree as ET def extract_username_via_xml(attribute): # 补全XML根节点避免解析报错 xml_str = f"<root>{attribute}</root>" root = ET.fromstring(xml_str) target_user = root.find(".//Data[@Name='TargetUserName']") return [' - '] if target_user is None else [target_user.text]
内容的提问来源于stack exchange,提问作者OverflowStack
相关产品推荐
相关产品推荐

