找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
热搜: 文档 工具 设计
查看: 112|回复: 0

兔子vCard editor v1.8(修复右键功能) 源码

[复制链接]

2万

主题

1249

回帖

2万

积分

超级版主

教育辅助界扛把子

附加身份标识
精华
1
热心
7
听众
1
威望
48
贡献
14309
违规
0
书币
49983
注册时间
2020-4-8

论坛元老灌水之王

发表于 2023-11-28 02:56 | 显示全部楼层 |阅读模式
通讯录里的有几千个电话号码,找手机不好整理,在电脑整理完毕后可以导入手机。作为备份。

用python写的,不尽完善的地方见谅,新手。
新手使用python打包的exe,文件有点大。
应该是里面有很多库的原因。python开发,没有加壳,无毒。
46个就监测出来一个恶意,我也不知道这个Systweak是什么杀毒的,
就一个读取文件转换文件的软件有啥恶意的。

[Python] 纯文本查看 复制代码
import tkinter as tk
from tkinter import ttk
from tkinter import filedialog
from tkinter import Menu
import vobject
import pandas as pd
import chardet

data = []
company_to_name = {}  # 用于存储公司名称到姓名的映射

def browse_file(file_path=None):
    if file_path is None:
        file_path = filedialog.askopenfilename(filetypes=[("vCard文件", "*.vcf")])
    if file_path:
        encoding = detect_encoding(file_path)
        if encoding:
            parse_vcf(file_path, encoding)

def detect_encoding(file_path):
    rawdata = open(file_path, 'rb').read()
    result = chardet.detect(rawdata)
    encoding = result['encoding']
    confidence = result['confidence']
    if confidence > 0.8:
        return encoding
    return 'utf-8'

def parse_vcf(file_path, encoding):
    data.clear()
    company_to_name.clear()
    try:
        with open(file_path, 'r', encoding=encoding, errors='ignore') as vcf_file:
            cards = vobject.readComponents(vcf_file)
            num_entries = 0
            for vcard in cards:
                name = ""
                company = ""
                phone_numbers = [""] * 3
                if hasattr(vcard, 'fn'):
                    name = vcard.fn.value.strip()
                if hasattr(vcard, 'org'):
                    company = vcard.org.value[0]
                    company_to_name[company] = name
                if hasattr(vcard, 'tel_list'):
                    tel_list = [tel.value.replace(" ", "").strip() for tel in vcard.tel_list if hasattr(tel, 'value')]
                    for i, tel in enumerate(tel_list):
                        if i < 3:
                            phone_numbers[i] = tel

                if name or company or any(phone_numbers):
                    data.append([name, company] + phone_numbers)
                    num_entries += 1

            if data:
                update_table()
                output_text.set(f"总条目数:{num_entries}")
            else:
                output_text.set("未找到有效的vCard条目")
    except Exception as e:
        output_text.set(f"错误:{str(e)}")

def reset_data():
    data.clear()
    update_table()
    output_text.set("数据已重置")

def add_to_table(name, phone_numbers, company):
    data.append([name, company] + phone_numbers)
    update_table()

def update_table():
    for i in table.get_children():
        table.delete(i)
    for i, row in enumerate(data):
        formatted_row = [item.strip() if isinstance(item, str) else item for item in row]
        table.insert("", "end", values=formatted_row)

def delete_empty_entries():
    global data  # 引用全局的 data 变量
    data = [entry for entry in data if any(entry[2:])]
    update_table()
    output_text.set(f"总条目数:{len(data)}")

def export_to_csv():
    file_path = filedialog.asksaveasfilename(defaultextension=".csv", filetypes=[("CSV文件", "*.csv")])
    if file_path:
        column_names = ["姓名", "公司", "电话号码1", "电话号码2", "电话号码3"]
        df = pd.DataFrame(data, columns=column_names)
        df.to_csv(file_path, index=False)

def copy_selected():
    selected = table.selection()
    if selected:
        item = table.selection()[0]
        column = table.identify_column(item)
        column_index = int(column.split('#')[-1]) - 1  # 获取选定单元格的列索引
        row = table.item(item)
        data_to_copy = row["values"][column_index]
        if data_to_copy is not None:
            clipboard = str(data_to_copy)
            root.clipboard_clear()
            root.clipboard_append(clipboard)
            root.update()

def create_table_menu(event):
    selected = table.selection()
    if selected:
        table_menu.delete(0, "end")  # 清空菜单项
        for i in range(len(table["columns"])):
            table_menu.add_command(label=f"复制列 {i + 1}", command=copy_selected)
        table_menu.post(event.x_root, event.y_root)

def delete_selected():
    selected = table.selection()
    if selected:
        for item in selected:
            table.delete(item)

def merge_duplicate_numbers():
    number_to_names = {}
    new_data = []

    for row in data:
        name = row[0]
        company = row[1]
        numbers = row[2:]
        if any(numbers):
            numbers_key = tuple(numbers)
            if numbers_key in number_to_names:
                number_to_names[numbers_key].append(name)
            else:
                number_to_names[numbers_key] = [name]
            new_data.append([" & ".join(number_to_names[numbers_key]), company] + list(numbers))
        else:
            new_data.append([name, company] + numbers)

    data.clear()
    data.extend(new_data)
    update_table()

def search_data():
    query = search_entry.get().strip().lower()
    if not query:
        update_table()
        return

    filtered_data = [entry for entry in data if any(query in value.lower() for value in entry)]
    update_table_with_filtered_data(filtered_data)

def update_table_with_filtered_data(filtered_data):
    for i in table.get_children():
        table.delete(i)
    for row in filtered_data:
        formatted_row = [item.strip if isinstance(item, str) else item for item in row]
        table.insert("", "end", values=formatted_row)

def save_as_vcf():
    file_path = filedialog.asksaveasfilename(defaultextension=".vcf", filetypes=[("VCF文件", "*.vcf")])
    if file_path:
        vcf_data = []
        for row in data:
            name, company, phone1, phone2, phone3 = row
            v = vobject.vCard()
            if name:
                v.add('fn').value = name
            if company:
                v.add('org').value = [company]
            if phone1:
                v.add('tel').value = phone1
            if phone2:
                v.add('tel').value = phone2
            if phone3:
                v.add('tel').value = phone3
            vcf_data.append(v.serialize())

        with open(file_path, 'w', encoding='utf-8') as vcf_file:
            vcf_file.write("\n".join(vcf_data))

root = tk.Tk()
root.title("兔子vCard Editor v1.6 By 阿修(吾爱破解论坛专版)")
root.resizable(False, False)  # 禁用窗口的最大化功能

main_frame = ttk.Frame(root)
main_frame.grid(column=0, row=0, padx=10, pady=10, sticky=(tk.W, tk.E, tk.N, tk.S))

# 左侧功能按钮
left_frame = ttk.Frame(main_frame)
left_frame.grid(column=0, row=0, padx=5, pady=5, sticky=tk.N)

browse_button = ttk.Button(left_frame, text="打开VCF文件", command=browse_file)
browse_button.grid(column=0, row=0, padx=5, pady=5, sticky=tk.W)

reset_button = ttk.Button(left_frame, text="重置数据", command=reset_data)
reset_button.grid(column=0, row=1, padx=5, pady=5, sticky=tk.W)

delete_empty_button = ttk.Button(left_frame, text="删除空号码", command=delete_empty_entries)
delete_empty_button.grid(column=0, row=2, padx=5, pady=5, sticky=tk.W)

merge_button = ttk.Button(left_frame, text="合并号码", command=merge_duplicate_numbers)
merge_button.grid(column=0, row=3, padx=5, pady=5, sticky=tk.W)

output_text = tk.StringVar()
output_label = ttk.Label(left_frame, textvariable=output_text, wraplength=200)
output_label.grid(column=0, row=4, padx=5, pady=5, sticky=tk.W)

# 中间表格
table_frame = ttk.Frame(main_frame)
table_frame.grid(column=1, row=0, padx=5, pady=5, sticky=(tk.W, tk.E))

# 设置表头样式
style = ttk.Style()
style.configure("Treeview.Heading", font=("Arial", 12, "bold"), background="lightgray")

table = ttk.Treeview(table_frame, columns=["姓名", "公司", "电话号码1", "电话号码2", "电话号码3"], show="headings")
table.heading("姓名", text="姓名", anchor="w")
table.heading("公司", text="公司", anchor="w")
table.heading("电话号码1", text="电话号码1", anchor="w")
table.heading("电话号码2", text="电话号码2", anchor="w")
table.heading("电话号码3", text="电话号码3", anchor="w")

# 设置列宽度
table.column("姓名", width=75)  # 将姓名的宽度改为75
table.column("公司", width=200)  # 将公司名称的宽度改为200
table.column("电话号码1", width=100)  # 将电话号码1的宽度改为150
table.column("电话号码2", width=100)  # 将电话号码2的宽度改为150
table.column("电话号码3", width=100)  # 将电话号码3的宽度改为150

table.pack(fill="both", expand=True)

# 添加右键菜单
table.bind('<Button-3>', create_table_menu)

# 创建右键菜单
table_menu = Menu(root, tearoff=0)
table_menu.add_separator()
table_menu.add_command(label="删除选定行", command=delete_selected)
table_menu.add_command(label="合并号码", command=merge_duplicate_numbers)

# 右侧功能按钮
right_frame = ttk.Frame(main_frame)
right_frame.grid(column=2, row=0, padx=5, pady=5, sticky=tk.N)

export_button = ttk.Button(right_frame, text="导出为CSV", command=export_to_csv)
export_button.grid(column=0, row=0, padx=5, pady=5, sticky=tk.W)

search_label = ttk.Label(right_frame, text="查询数据:")
search_label.grid(column=0, row=1, padx=5, pady=5, sticky=tk.W)

search_entry = ttk.Entry(right_frame)
search_entry.grid(column=0, row=2, padx=5, pady=5, sticky=tk.W)

search_button = ttk.Button(right_frame, text="查询", command=search_data)
search_button.grid(column=0, row=3, padx=5, pady=5, sticky=tk.W)

save_as_vcf_button = ttk.Button(right_frame, text="保存为VCF", command=save_as_vcf)
save_as_vcf_button.grid(column=0, row=4, padx=5, pady=5, sticky=tk.W)

main_frame.columnconfigure(1, weight=1)
main_frame.rowconfigure(0, weight=1)

root.mainloop()



Great works are not done by strength, but by persistence! 历尽艰辛的飞升者,成了围剿孙悟空的十万天兵之一。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则 需要先绑定手机号


免责声明:
本站所发布的第三方软件及资源(包括但不仅限于文字/图片/音频/视频等仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如果您喜欢某程序或某个资源,请支持正版软件及版权方利益,注册或购买,得到更好的正版服务。如有侵权请邮件与我们联系处理。

Mail To: admin@cdsy.xyz

QQ|Archiver|手机版|小黑屋|城东书院 ( 湘ICP备19021508号-1|湘公网安备 43102202000103号 )

GMT+8, 2024-11-21 20:42 , Processed in 0.049840 second(s), 28 queries .

Powered by Discuz! CDSY.XYZ

Copyright © 2019-2023, Tencent Cloud.

快速回复 返回顶部 返回列表