【问题标题】:Compare two vcards比较两张电子名片
【发布时间】:2020-11-24 21:31:24
【问题描述】:

我有两张电子名片:

vcard1 = "BEGIN:VCARD
          VERSION:3.0
          N;CHARSET=UTF-8:Name;;;;
          TEL:0005555000
          END:VCARD"

vcard2 = "BEGIN:VCARD
      VERSION:3.0
      N;CHARSET=UTF-8:Name;;;;
      TEL:0005555000
      EMAIL;CHARSET=UTF-8:my_email@email.com
      END:VCARD"

如您所见,唯一的区别是第二个 vcard 有一个附加属性,即 EMAIL?使用代码可以认为这两个电子名片是平等的吗?

import vobject
print(vobject.readOne(vcard1).serialize()==vobject.readOne(vcard2).serialize())

【问题讨论】:

  • 它们可以是你想要的任何东西。这就是编程的伟大之处。您首先需要做的是对两张卡片相同的原因进行完整描述。您可以谈论必须相同的事物,也可以谈论不必相同的事物,或者两者兼而有之。 EMAIL 是唯一可能不同但对象仍然相等的属性吗?只有当你可以向其他人描述(例如在这个问题中)是什么决定了匹配还是不匹配时,谈论代码才有意义。
  • 就你展示的代码而言,你展示的两个值都是字符串,所以它们已经被序列化了。如果您将它们作为字符串进行比较,它们显然会被测试为不同。您可能希望解析这些字符串并将它们转换为对象(反序列化它们),以便对它们进行非平凡的比较。您可能希望为每个键和值都是字符串的字典创建一个字典。然后,您可以逐个键比较键,并根据您对使这些对象中的两个相同的原因的描述来决定比较哪些键和哪些键。
  • 您好@steve,感谢您的回复,我编辑了我的代码以便我们不再比较两个字符串

标签: python python-2.7 vcf-vcard vobject


【解决方案1】:

解决方案

任何比较的第一条规则是定义比较的基础。如果您正在寻找可以比较的数量,您甚至可以比较苹果和橙子:例如“多少个苹果与橙子” 或“5 个苹果与 5 个橙子的重量” .要点是基本比较基础的定义必须明确。

注意:我将使用下面 Dummy Data 部分的数据。

将此概念扩展到您的用例,您可以将vcards 与每个字段进行比较,然后还可以与所有字段进行比较。例如,我向您展示了三种比较它们的方法:

  • Example A1:比较vcard1vcard2 之间的仅常见文件。
  • Example A2:比较vcard1vcard2之间的所有文件。
  • Example A3仅比较 vcard1vcard2 之间的常见用户指定的文件。

显然,在这种情况下,如果您比较vcard1vcard2 的序列化版本,它将返回False,因为这两个vcard 的内容不同。

vc1.serialize()==vc2.serialize() # False

示例

在每种情况下 (A1, A2, A3),自定义函数 compare_vcards() 返回两件事:

  • matchdict,在每个字段级别进行匹配
  • summarydict,给出聚合的绝对匹配(如果所有字段都匹配)和相对(比例:[0,1])匹配(适用于部分匹配)。

但是您必须定义自己的业务逻辑来确定您认为什么是匹配的,什么不是。不过,我在这里展示的内容应该可以帮助您入门。

## Example - A1
#  Compare ONLY COMMON fields b/w vc1 and vc2
match, summary = compare_vcards(vc1, vc2, mode='common')
print(f'match:   \t{match}')
print(f'summary: \t{summary}')

## Output
# match:    {'n': True, 'tel': True, 'version': True}
# summary:  {'abs_match': True, 'rel_match': 1.0}

## Example - A2
#  Compare ALL fields b/w vc1 and vc2
match, summary = compare_vcards(vc1, vc2, mode='all')
print(f'match:   \t{match}')
print(f'summary: \t{summary}')

## Output
# match:    {'tel': True, 'email': False, 'n': True, 'version': True}
# summary:  {'abs_match': False, 'rel_match': 0.75}

## Example - A3
#  Compare ONLY COMMON USER-SPECIFIED fields b/w vc1 and vc2
match, summary = compare_vcards(vc1, vc2, fields=['email', 'n', 'tel'])
print(f'match:   \t{match}')
print(f'summary: \t{summary}')

## Output
# match:    {'email': False, 'n': True, 'tel': True}
# summary:  {'abs_match': False, 'rel_match': 0.6666666666666666}

代码

def get_fields(vc1, vc2, mode='common'):
    if mode=='common':
        fields = set(vc1.sortChildKeys()).intersection(set(vc2.sortChildKeys()))
    else:
        # mode = 'all'
        fields = set(vc1.sortChildKeys()).union(set(vc2.sortChildKeys()))
    return fields

def compare_vcards(vc1, vc2, fields=None, mode='common'):
    if fields is None:
        fields = get_fields(vc1, vc2, mode=mode) 
    match = dict(
        (field, str(vc1.getChildValue(field)).strip()==str(vc2.getChildValue(field)).strip()) 
        for field in fields
    )
    summary = {
        'abs_match': all(match.values()), 
        'rel_match': sum(match.values()) / len(match)
    }
    return match, summary

虚拟数据

vcard1 = """
BEGIN:VCARD
VERSION:3.0
N;CHARSET=UTF-8:Name;;;;
TEL:0005555000
END:VCARD
"""

vcard2 = """
BEGIN:VCARD
VERSION:3.0
N;CHARSET=UTF-8:Name;;;;
TEL:0005555000
EMAIL;CHARSET=UTF-8:my_email@email.com
END:VCARD
"""

# pip install vobject
import vobject

vc1 = vobject.readOne(vcard1)
vc2 = vobject.readOne(vcard2)

参考文献

【讨论】:

  • @faith 这有帮助吗?如果您有任何问题,请告诉我。
  • @faith:谢谢accepting 的回答。我很高兴你发现它有用。也请考虑 voting-up
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-28
  • 1970-01-01
  • 2019-07-17
  • 2011-10-08
相关资源
最近更新 更多