RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1599809
Accepted
ykoavlil
ykoavlil
Asked:2024-11-15 01:55:46 +0000 UTC2024-11-15 01:55:46 +0000 UTC 2024-11-15 01:55:46 +0000 UTC

从 .vcf 文件 (VCARD) 输出联系人列表

  • 772

扩展名为 .vcf (VCARD) 的文件片段

BEGIN:VCARD
VERSION:2.1
N;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:;=D0=9C=D0=A2=D0=A1;;;
FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=D0=9C=D0=A2=D0=A1
TEL;CELL;PREF:+78002500123
END:VCARD
BEGIN:VCARD
VERSION:2.1
N;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:;=D0=A1=D0=BB=D1=83=D0=B6=D0=B1=D0=B0=20=D1=81=D0=BF=D0=B0=D1=81=D0=B5=
=D0=BD=D0=B8=D1=8F;;;
FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=D0=A1=D0=BB=D1=83=D0=B6=D0=B1=D0=B0=20=D1=81=D0=BF=D0=B0=D1=81=D0=B5=
=D0=BD=D0=B8=D1=8F
TEL;CELL;PREF:112
END:VCARD

我的代码

import vobject

with open('test.vcf') as source_file:
    vcf_read_components = vobject.readComponents(source_file)
    for item in vcf_read_components:
        print(item)

出现解析错误

Traceback (most recent call last):
  File "/home/xxx/experiments/book.py", line 5, in <module>
    for item in vcf_read_components:
  File "/home/xxx/experiments/venv/lib/python3.11/site-packages/vobject/base.py", line 1166, in readComponents
    vline = textLineToContentLine(line, n)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/xxx/experiments/venv/lib/python3.11/site-packages/vobject/base.py", line 984, in textLineToContentLine
    return ContentLine(*parseLine(text, n), **{"encoded": True, "lineNumber": n})
                        ^^^^^^^^^^^^^^^^^^
  File "/home/xxx/experiments/venv/lib/python3.11/site-packages/vobject/base.py", line 864, in parseLine
    raise ParseError("Failed to parse line: {0!s}".format(line), lineNumber)
vobject.base.ParseError: At line 19: Failed to parse line: =D0=BD=D0=B8=D1=8F;;;
<VCARD| [<VERSION{}2.1>, <FN{'CHARSET': ['UTF-8']}МТС>, <N{'CHARSET': ['UTF-8']} МТС   >, <TEL{}+78002500123>]>

从 2024 年 11 月 15 日起,当联系人拥有多个号码时进行澄清。

BEGIN:VCARD
VERSION:2.1
N;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=D0=94=D0=BE=D1=80=D1=84;=D0=9C=D0=B0=D0=BA=D1=81;;;
FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=D0=9C=D0=B0=D0=BA=D1=81=20=D0=94=D0=BE=D1=80=D1=84
TEL;CELL:+79128051234
TEL;CELL:+79097484321
END:VCARD
import vobject

with open('test.vcf') as source_file:
    vcf_read_components = vobject.readComponents(source_file, allowQP=True)
    for item in vcf_read_components:
        print(item)
        print(item.fn.value)
        print(item.tel.value)

item.tel.value仅返回第一个

<VCARD| [<VERSION{}2.1>, <FN{'CHARSET': ['UTF-8']}Макс Дорф>, <N{'CHARSET': ['UTF-8']} Макс  Дорф >, <TEL{}+79128051234>, <TEL{}+79097484321>]>
Макс Дорф
+79128051234
python
  • 3 3 个回答
  • 68 Views

3 个回答

  • Voted
  1. Oopss
    2024-11-15T03:10:25Z2024-11-15T03:10:25Z

    =D0=A1=D0=BB=D1=83=D0=B6=D0=B1=D0=B0=20=D1=81=D0=BF=D0=B0=D1=81=D0=B5 ->= = <-解析器在这里死掉 D0=BD=D0=B8=D1=8F;;;

    import vobject
    import re
    
    s = '''BEGIN:VCARD
    VERSION:2.1
    N;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:;=D0=9C=D0=A2=D0=A1;;;
    FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=D0=9C=D0=A2=D0=A1
    TEL;CELL;PREF:+78002500123
    END:VCARD
    BEGIN:VCARD
    VERSION:2.1
    N;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:;=D0=A1=D0=BB=D1=83=D0=B6=D0=B1=D0=B0=20=D1=81=D0=BF=
    =D0=B0=D1=81=D0=B5=D0=BD=D0=B8=D1=8F;;;
    FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=D0=A1=D0=BB=D1=83=D0=B6=D0=B1=D0=B0=20=D1=81=D0=BF=
    =D0=B0=D1=81=D0=B5=D0=BD=D0=B8=D1=8F
    TEL;CELL;PREF:112
    END:VCARD
    BEGIN:VCARD
    VERSION:2.1
    N:;0423;;;
    FN:;0423
    TEL;CELL:+79272686770
    TEL:+79277767901
    X-CLASS:private
    X-CATEGORIES:
    REV:20121127T052113Z
    END:VCARD
    BEGIN:VCARD
    VERSION:2.1
    N;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=D0=94=D0=BE=D1=80=D1=84;=D0=9C=D0=B0=D0=BA=D1=81;;;
    FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=D0=9C=D0=B0=D0=BA=D1=81=20=D0=94=D0=BE=D1=80=D1=84
    TEL;CELL:+79128051234
    TEL;CELL:+79097484321
    END:VCARD'''
    
    # Регулярное выражение для поиска частей между BEGIN:VCARD и END:VCARD
    pattern = re.compile(r'(BEGIN:VCARD.*?END:VCARD)', re.DOTALL)
    pattern_remove_eq = re.compile(r'=\n=')
    s = pattern_remove_eq.sub('=', s)
    
    # Разделение строки на части
    vcard_parts = pattern.findall(s)
    
    # Вывод каждой части
    for i, part in enumerate(vcard_parts, 1):
        print(i, '------------')
        v = vobject.readOne(part)
        v.prettyPrint()
    
        print(v.n.value)
        print(v.fn.value)
        if len(v.tel_list) > 1:
            #Списком
            print(f'Список {v.tel_list}')
            #Или так по одному
            for t in v.tel_list:
                print(f'Каждый {t.value}')
        else:
            print(v.tel.value)
    

    1 ------------
     VCARD
        VERSION: 2.1
        N:  МТС   
        params for  N:
           CHARSET ['UTF-8']
        FN: МТС
        params for  FN:
           CHARSET ['UTF-8']
        TEL: +78002500123
     МТС   
    МТС
    +78002500123
    2 ------------
     VCARD
        VERSION: 2.1
        N:  Служба спасения   
        params for  N:
           CHARSET ['UTF-8']
        FN: Служба спасения
        params for  FN:
           CHARSET ['UTF-8']
        TEL: 112
     Служба спасения   
    Служба спасения
    112
    3 ------------
     VCARD
        VERSION: 2.1
        N:  0423   
        FN: ;0423
        TEL: +79272686770
        TEL: +79277767901
        X-CLASS: private
        X-CATEGORIES: 
        REV: 20121127T052113Z
     0423   
    ;0423
    Список [<TEL{}+79272686770>, <TEL{}+79277767901>]
    Каждый +79272686770
    Каждый +79277767901
    4 ------------
     VCARD
        VERSION: 2.1
        N:  Макс  Дорф 
        params for  N:
           CHARSET ['UTF-8']
        FN: Макс Дорф
        params for  FN:
           CHARSET ['UTF-8']
        TEL: +79128051234
        TEL: +79097484321
     Макс  Дорф 
    Макс Дорф
    Список [<TEL{}+79128051234>, <TEL{}+79097484321>]
    Каждый +79128051234
    Каждый +79097484321
    
    • 3
  2. Best Answer
    strawdog
    2024-11-15T19:05:57Z2024-11-15T19:05:57Z

    为了解决这个问题,通常启用quoted-printable数据处理就足够了:

    vobject.readComponents(source_file, allowQP=True)
    
    • 2
  3. ykoavlil
    2024-11-16T23:43:14Z2024-11-16T23:43:14Z

    我考虑了这些建议(再次感谢大家!)并添加了一些。这是带注释的代码:

    import vobject
    import datetime
    
    with open('test.vcf') as source_file:
        contacts = vobject.readComponents(source_file, allowQP=True)
        for contact in contacts:
            # Имя, отчество и фамилия
            print(contact.fn.value)
    
            # Если у контакта указан день рождения выводим его в российском формате даты (DD.MM.YYYY)
            # Через разницу текущая дата и день рождения определяем сколько лет
            # Обрабатываем исключение если данного поля нет
            try:
                birthday = datetime.date.fromisoformat(contact.bday.value)
                today = datetime.date.today()
                years = (today - birthday).days // 365
                print(f'{birthday.strftime("%d.%m.%Y")} ({years} лет)')
            except AttributeError:
                pass
    
            # Номеров телефонов может быть несколько выводим их все
            for phone_number in contact.tel_list:
                print(phone_number.value)
    
            # На основе типа определяем просто его вывести (если строка) или нужно склеивать из строк (список)
            # Обрабатываем исключение если его нет
            try:
                for address in contact.adr_list:
                    street = address.value.street
                    if isinstance(street, str):
                        print(street)
                    else:
                        print(''.join(street))
            except AttributeError:
                pass
    
            print()
    

    结果:

    Василий Петрович
    10.12.1964 (59 лет)
    +11111111111
    
    Иван Иванович Иванов
    +22222222222
    +33333333333
    Ленина 1 кв. 1
    Октябрьская 1 кв. 1
    
    • 1

相关问题

  • 是否可以以某种方式自定义 QTabWidget?

  • telebot.anihelper.ApiException 错误

  • Python。检查一个数字是否是 3 的幂。输出 无

  • 解析多个响应

  • 交换两个数组的元素,以便它们的新内容也反转

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    我看不懂措辞

    • 1 个回答
  • Marko Smith

    请求的模块“del”不提供名为“default”的导出

    • 3 个回答
  • Marko Smith

    "!+tab" 在 HTML 的 vs 代码中不起作用

    • 5 个回答
  • Marko Smith

    我正在尝试解决“猜词”的问题。Python

    • 2 个回答
  • Marko Smith

    可以使用哪些命令将当前指针移动到指定的提交而不更改工作目录中的文件?

    • 1 个回答
  • Marko Smith

    Python解析野莓

    • 1 个回答
  • Marko Smith

    问题:“警告:检查最新版本的 pip 时出错。”

    • 2 个回答
  • Marko Smith

    帮助编写一个用值填充变量的循环。解决这个问题

    • 2 个回答
  • Marko Smith

    尽管依赖数组为空,但在渲染上调用了 2 次 useEffect

    • 2 个回答
  • Marko Smith

    数据不通过 Telegram.WebApp.sendData 发送

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5