Google Desktop: now a widget engine

谷歌通过更新其桌面小工具引擎,不仅增强了品牌影响力,还显著提升了iGoogle首页的使用率。此举可能威胁到雅虎小工具的主导地位,并且表明谷歌正采取行动以赶上并超越竞争对手。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Google Desktop:

Google Desktop until not long ago worked as the right way to gain desktop search powered by google along a way to get shortcuts for google services. that is no more because now Google desktop is a Widget Engine in a move that really put them in advantage over Yahoo, something that is not so surprising if you care to read my review of the Yahoo Widget engine. the pint is that this move allow Google not only to power up their brand on the desktop but also boost significantly their Igoogle start page that was starting to slow down in adoption some months back because google gadgets are compatible with google desktop.

With this swift move, google could have put in jeopardy Yahoo Widgets dominance very fast, if Yahoo don´t respond before the year ends, it could be game over for them in terms of dominance if it not already is.

Google desktop also respond to 2007 "year of the widget" theme that turned to be totally true.

What is Google aiming for?

is a question that most be asking themselves, and the answer is "catch up and extend". something that can be pointed out to any of the big 3. Google Widget initiatives were pretty weak just 3 months ago and now look at them: there is widget adsense, igoogle got quite ramped up and now the final part of that angle is finally completed with the revamp of Google desktop.

By adopting a Bridge philosophy with the way their gadgets should work in the desktop and online ( The same) they can counteract Yahoo and Microsoft advancements with their respective start pages, they can take a shot at Yahoo domance with a hefty chance of winning and become the number one widget provider, take ashot at MS because not having a version of Windows Vista Sidebar for XP, a system that easily will reach a 10 year relevance period and also counter act the way MS is bridging their gadgets in the Windows Ecosystem before it could gain dominance.

Google has also showed quite a bold stance by duplicating the vista Sidebar for XP and even as a daring replacement for it in Vista. certainly a move Google would not have dared to make just a year ago…

Google Desktop Sidebar

What does it means?

That the widget game is getting even bigger and changing as fast as the landscape of web development. it also means that if the trends are right we should have only a handful of "universal" widget platforms when all is said and done and that even then, with all the widget translating services, there will be a easy way to shift from one to the other and that the change from online and desktop widgets will be not existing in terms of form and use.

Igoogle meet Desktop gadgets

 

import locale locale.setlocale(locale.LC_ALL, 'chinese') import tkinter as tk from tkinter import filedialog, messagebox, ttk, scrolledtext import csv from datetime import datetime import logging import os from collections import defaultdict class CSVProcessorApp: def __init__(self, root): self.root = root self.root.title("CSV_ProcessPro") self.root.geometry("800x600") # 调整窗口大小 self.root.resizable(False, False) # 禁止调整窗口大小 # 初始化变量 self.file_path = tk.StringVar() self.csv_data = [] self.headers = [] self.setup_variables() # 初始化日志 self.setup_logging() # 创建UI self.create_widgets() # 设置全局样式 self.setup_styles() def setup_styles(self): """设置全局样式""" self.style = ttk.Style() self.style.configure("TFrame", background="#f0f0f0") self.style.configure("TLabel", background="#f0f0f0", font=('Arial', 9)) self.style.configure("TButton", font=('Arial', 9, 'bold')) self.style.configure("Accent.TButton", foreground="black", font=('Arial', 9, 'bold'), borderwidth=2, relief="raised") self.style.map("Accent.TButton", background=[("active", "#4a90e2"), ("!active", "#d4e6ff")], bordercolor=[("active", "#4a90e2"), ("!active", "#ffcc00")]) self.style.configure("Remove.TButton", foreground="black", font=('Arial', 8), background="#ffcccc", borderwidth=1, relief="solid") self.style.map("Remove.TButton", background=[("active", "#ff9999"), ("!active", "#ffcccc")]) def setup_variables(self): """初始化所有动态变量""" # 排序相关 self.sort_header = tk.StringVar() self.sort_order = tk.StringVar(value="升序") # 去重相关 self.dedupe_header = tk.StringVar() # 删除行相关 self.delete_keyword = tk.StringVar() self.delete_column = tk.StringVar() self.delete_case_sensitive = tk.BooleanVar() # 合并文件相关 self.merge_file_paths = [] self.merge_column = tk.StringVar() # 状态变量 self.enable_sort = tk.BooleanVar() self.enable_dedupe = tk.BooleanVar() self.enable_custom_letter_sort = tk.BooleanVar() self.letter_range_start = tk.StringVar(value="A") self.letter_range_end = tk.StringVar(value="Z") def setup_logging(self): """配置日志记录""" logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', handlers=[ logging.FileHandler('csv_processor.log', encoding='utf-8'), logging.StreamHandler() ] ) self.logger = logging.getLogger(__name__) self.logger.info("===== 程序启动 =====") def create_widgets(self): """创建所有界面组件""" # 主容器 main_container = ttk.Frame(self.root, padding=5) main_container.pack(fill=tk.BOTH, expand=True) # 使用notebook分页组织功能 self.notebook = ttk.Notebook(main_container) self.notebook.pack(fill=tk.BOTH, expand=True) # 创建各个标签页 self.create_file_tab() self.create_process_tab() self.create_delete_tab() self.create_merge_tab() self.create_log_tab() def create_file_tab(self): """创建文件操作标签页""" tab = ttk.Frame(self.notebook) self.notebook.add(tab, text="文件操作") # 文件选择部分 frame = ttk.LabelFrame(tab, text="CSV文件选择", padding=10) frame.pack(fill=tk.X, padx=5, pady=5) ttk.Label(frame, text="文件路径:").grid(row=0, column=0, sticky=tk.W) ttk.Entry(frame, textvariable=self.file_path, width=40).grid(row=0, column=1, sticky=tk.EW) ttk.Button(frame, text="浏览", command=self.select_file).grid(row=0, column=2, padx=5) # 文件信息显示 self.file_info = scrolledtext.ScrolledText(tab, height=8, width=80) self.file_info.pack(fill=tk.X, padx=5, pady=5) def create_process_tab(self): """创建数据处理标签页""" tab = ttk.Frame(self.notebook) self.notebook.add(tab, text="排序/去重") # 排序选项部分 frame = ttk.LabelFrame(tab, text="排序选项", padding=10) frame.pack(fill=tk.X, padx=5, pady=5) ttk.Checkbutton(frame, text="启用排序", variable=self.enable_sort, command=self.toggle_sort).grid(row=0, column=0, sticky=tk.W) ttk.Label(frame, text="排序表头:").grid(row=1, column=0, sticky=tk.W) self.sort_header_combobox = ttk.Combobox(frame, textvariable=self.sort_header, state="readonly") self.sort_header_combobox.grid(row=1, column=1, sticky=tk.EW) ttk.Label(frame, text="排序方式:").grid(row=2, column=0, sticky=tk.W) self.sort_order_combobox = ttk.Combobox(frame, textvariable=self.sort_order, values=["升序", "降序", "自定义字母排序"]) self.sort_order_combobox.grid(row=2, column=1, sticky=tk.W) # 自定义字母排序范围 ttk.Checkbutton(frame, text="启用字母范围过滤", variable=self.enable_custom_letter_sort, command=self.toggle_letter_sort).grid(row=3, column=0, sticky=tk.W) ttk.Label(frame, text="字母范围:").grid(row=4, column=0, sticky=tk.W) ttk.Entry(frame, textvariable=self.letter_range_start, width=5).grid(row=4, column=1, sticky=tk.W) ttk.Label(frame, text="到").grid(row=4, column=2) ttk.Entry(frame, textvariable=self.letter_range_end, width=5).grid(row=4, column=3, sticky=tk.W) # 去重选项部分 frame = ttk.LabelFrame(tab, text="去重选项", padding=10) frame.pack(fill=tk.X, padx=5, pady=5) ttk.Checkbutton(frame, text="启用去重", variable=self.enable_dedupe, command=self.toggle_dedupe).grid(row=0, column=0, sticky=tk.W) ttk.Label(frame, text="去重表头:").grid(row=1, column=0, sticky=tk.W) self.dedupe_header_combobox = ttk.Combobox(frame, textvariable=self.dedupe_header, state="readonly") self.dedupe_header_combobox.grid(row=1, column=1, sticky=tk.EW) # 处理按钮 btn_frame = ttk.Frame(tab) btn_frame.pack(pady=10) ttk.Button(btn_frame, text="处理并保存到桌面", command=self.process_csv, style="Accent.TButton").pack() def create_delete_tab(self): """创建删除行标签页""" tab = ttk.Frame(self.notebook) self.notebook.add(tab, text="删除行") frame = ttk.LabelFrame(tab, text="删除包含指定字符的行", padding=10) frame.pack(fill=tk.X, padx=5, pady=5) # 删除条件设置 ttk.Label(frame, text="搜索列:").grid(row=0, column=0, sticky=tk.W) self.delete_column_combobox = ttk.Combobox(frame, textvariable=self.delete_column, state="readonly") self.delete_column_combobox.grid(row=0, column=1, sticky=tk.EW) ttk.Label(frame, text="关键字:").grid(row=1, column=0, sticky=tk.W) ttk.Entry(frame, textvariable=self.delete_keyword).grid(row=1, column=1, sticky=tk.EW) ttk.Checkbutton(frame, text="区分大小写", variable=self.delete_case_sensitive).grid(row=2, column=0, sticky=tk.W) # 执行按钮 btn_frame = ttk.Frame(tab) btn_frame.pack(pady=10) ttk.Button(btn_frame, text="执行删除并保存到桌面", command=self.delete_rows_with_keyword, style="Accent.TButton").pack() def create_merge_tab(self): """创建文件合并标签页""" tab = ttk.Frame(self.notebook) self.notebook.add(tab, text="文件合并") # 合并文件部分 frame = ttk.LabelFrame(tab, text="合并CSV文件", padding=10) frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5) # 文件列表容器 list_frame = ttk.Frame(frame) list_frame.pack(fill=tk.BOTH, expand=True) ttk.Label(list_frame, text="已选择文件:").grid(row=0, column=0, sticky=tk.W) # 文件列表和滚动条 self.merge_file_canvas = tk.Canvas(list_frame, height=150) self.merge_file_canvas.grid(row=1, column=0, sticky=tk.EW) scrollbar = ttk.Scrollbar(list_frame, orient="vertical", command=self.merge_file_canvas.yview) scrollbar.grid(row=1, column=1, sticky=tk.NS) self.merge_file_canvas.configure(yscrollcommand=scrollbar.set) self.merge_file_frame = ttk.Frame(self.merge_file_canvas) self.merge_file_canvas.create_window((0, 0), window=self.merge_file_frame, anchor="nw") # 按钮区域 btn_frame = ttk.Frame(frame) btn_frame.pack(fill=tk.X, pady=5) ttk.Button(btn_frame, text="添加文件", command=self.add_merge_file).pack(side=tk.LEFT, padx=5) ttk.Button(btn_frame, text="清空列表", command=self.clear_merge_list).pack(side=tk.LEFT, padx=5) # 合并选项 opt_frame = ttk.Frame(frame) opt_frame.pack(fill=tk.X, pady=5) ttk.Label(opt_frame, text="合并依据列(可选):").grid(row=0, column=0, sticky=tk.W) self.merge_column_combo = ttk.Combobox(opt_frame, textvariable=self.merge_column, state="readonly") self.merge_column_combo.grid(row=0, column=1, sticky=tk.EW) # 合并按钮 btn_frame = ttk.Frame(tab) btn_frame.pack(pady=10) ttk.Button(btn_frame, text="执行合并并保存到桌面", command=self.merge_csv_files, style="Accent.TButton").pack() def create_log_tab(self): """创建日志标签页""" tab = ttk.Frame(self.notebook) self.notebook.add(tab, text="运行日志") self.log_text = scrolledtext.ScrolledText(tab, height=15, width=80) self.log_text.pack(fill=tk.BOTH, expand=True, padx=5, pady=5) def log_message(self, message, level="info"): """记录日志并显示在GUI中""" log_methods = { "info": self.logger.info, "error": self.logger.error, "warning": self.logger.warning } # 记录到日志文件 log_methods.get(level, self.logger.info)(message) # 显示在GUI日志标签页 timestamp = datetime.now().strftime("%H:%M:%S") tagged_msg = f"[{timestamp}] {message}" self.log_text.insert(tk.END, tagged_msg + "\n") self.log_text.see(tk.END) # 同时在文件信息标签页显示重要信息 if level in ["error", "warning"]: self.file_info.config(state=tk.NORMAL) self.file_info.insert(tk.END, tagged_msg + "\n") self.file_info.config(state=tk.DISABLED) self.file_info.see(tk.END) def select_file(self): """选择CSV文件""" file_path = filedialog.askopenfilename( title="选择CSV文件", filetypes=[("CSV文件", "*.csv"), ("文本文件", "*.txt"), ("所有文件", "*.*")] ) if file_path: self.file_path.set(file_path) self.log_message(f"已选择文件: {file_path}") self.load_csv(file_path) def load_csv(self, file_path): """加载CSV文件内容""" try: with open(file_path, 'r', encoding='utf-8-sig') as file: reader = csv.reader(file) self.csv_data = list(reader) if len(self.csv_data) > 0: self.headers = self.csv_data[0] self.update_ui_with_headers() # 显示文件信息 self.show_file_info(file_path) self.log_message(f"文件加载成功,共 {len(self.csv_data)} 行") else: raise ValueError("文件为空或格式不正确") except Exception as e: error_msg = f"读取CSV文件失败: {str(e)}" self.log_message(error_msg, "error") messagebox.showerror("错误", error_msg) def show_file_info(self, file_path): """显示文件信息""" self.file_info.config(state=tk.NORMAL) self.file_info.delete(1.0, tk.END) info = [ f"文件路径: {file_path}", f"总行数: {len(self.csv_data)}", f"列数: {len(self.headers)}", f"表头: {', '.join(self.headers)}", "="*40, "前5行数据预览:" ] self.file_info.insert(tk.END, "\n".join(info) + "\n") # 显示前5行数据 for i, row in enumerate(self.csv_data[:5], 1): self.file_info.insert(tk.END, f"{i}. {', '.join(row)}\n") self.file_info.config(state=tk.DISABLED) def update_ui_with_headers(self): """根据加载的CSV更新UI元素""" # 更新所有下拉框 for combo in [ self.sort_header_combobox, self.dedupe_header_combobox, self.delete_column_combobox, self.merge_column_combo ]: combo['values'] = self.headers # 设置默认值 if self.headers: self.sort_header.set(self.headers[0]) self.dedupe_header.set(self.headers[0]) self.delete_column.set(self.headers[0]) self.merge_column.set("") def toggle_sort(self): """切换排序功能的启用状态""" state = "normal" if self.enable_sort.get() else "disabled" self.sort_header_combobox['state'] = state self.sort_order_combobox['state'] = state self.toggle_letter_sort() self.log_message(f"排序功能 {'启用' if self.enable_sort.get() else '禁用'}") def toggle_dedupe(self): """切换去重功能的启用状态""" state = "normal" if self.enable_dedupe.get() else "disabled" self.dedupe_header_combobox['state'] = state self.log_message(f"去重功能 {'启用' if self.enable_dedupe.get() else '禁用'}") def toggle_letter_sort(self): """控制字母范围输入框的启用状态""" if not self.enable_sort.get(): return state = "normal" if self.enable_custom_letter_sort.get() else "disabled" self.letter_range_start_entry['state'] = state self.letter_range_end_entry['state'] = state self.log_message(f"字母范围过滤 {'启用' if self.enable_custom_letter_sort.get() else '禁用'}") def add_merge_file(self): """添加要合并的文件""" file_paths = filedialog.askopenfilenames( title="选择要合并的CSV文件", filetypes=[("CSV文件", "*.csv"), ("文本文件", "*.txt"), ("所有文件", "*.*")] ) if file_paths: for path in file_paths: if path not in self.merge_file_paths: self.merge_file_paths.append(path) self.update_merge_file_list() def clear_merge_list(self): """清空合并文件列表""" if self.merge_file_paths: self.merge_file_paths = [] self.update_merge_file_list() self.log_message("已清空合并文件列表") def update_merge_file_list(self): """更新合并文件列表显示""" # 清除现有内容 for widget in self.merge_file_frame.winfo_children(): widget.destroy() if not self.merge_file_paths: ttk.Label(self.merge_file_frame, text="尚未选择任何文件").pack() self.merge_file_canvas.configure(scrollregion=self.merge_file_canvas.bbox("all")) return # 添加文件列表 for i, path in enumerate(self.merge_file_paths): row_frame = ttk.Frame(self.merge_file_frame) row_frame.pack(fill=tk.X, pady=2) ttk.Label(row_frame, text=f"{i+1}. {os.path.basename(path)}", width=40, anchor="w").pack(side=tk.LEFT) ttk.Button(row_frame, text="移除", command=lambda p=path: self.remove_merge_file(p), style="Remove.TButton").pack(side=tk.LEFT, padx=2) # 更新滚动区域 self.merge_file_frame.update_idletasks() self.merge_file_canvas.configure(scrollregion=self.merge_file_canvas.bbox("all")) def remove_merge_file(self, file_path): """移除指定的合并文件""" if file_path in self.merge_file_paths: self.merge_file_paths.remove(file_path) self.update_merge_file_list() self.log_message(f"已移除文件: {file_path}") def delete_rows_with_keyword(self): """删除包含关键字的行并保存到桌面""" if not self.file_path.get(): messagebox.showwarning("警告", "请先选择CSV文件") return column = self.delete_column.get() keyword = self.delete_keyword.get() if not column: messagebox.showwarning("警告", "请选择要搜索的列") return if not keyword: messagebox.showwarning("警告", "请输入要搜索的关键字") return try: col_index = self.headers.index(column) case_sensitive = self.delete_case_sensitive.get() if not case_sensitive: keyword = keyword.lower() new_data = [self.headers] deleted_count = 0 for row in self.csv_data[1:]: if len(row) > col_index: value = row[col_index] compare_value = value if case_sensitive else value.lower() if keyword not in compare_value: new_data.append(row) else: deleted_count += 1 if deleted_count == 0: messagebox.showinfo("信息", "没有找到包含关键字的行") return # 生成保存路径 operation = f"deleted_{keyword}" save_path = self.generate_filename(self.file_path.get(), operation) # 保存文件 self.save_csv_file(new_data, save_path) # 更新当前数据 self.csv_data = new_data self.log_message(f"已删除 {deleted_count} 行包含关键字 '{keyword}' 的数据") messagebox.showinfo("成功", f"已删除 {deleted_count} 行,结果已保存到桌面:\n{os.path.basename(save_path)}") except Exception as e: error_msg = f"删除行时出错: {str(e)}" self.log_message(error_msg, "error") messagebox.showerror("错误", error_msg) def get_desktop_path(self): """获取桌面路径""" try: desktop = os.path.join(os.path.join(os.environ['USERPROFILE']), 'Desktop') if os.path.exists(desktop): return desktop except KeyError: pass # 如果上面的方法失败,尝试其他方法 desktop = os.path.join(os.path.expanduser('~'), 'Desktop') if os.path.exists(desktop): return desktop # 如果还是失败,返回当前目录 return os.getcwd() def generate_filename(self, original_name, operation): """生成新的文件名""" if not original_name: original_name = "processed" base = os.path.basename(original_name) name, ext = os.path.splitext(base) # 清理操作名称中的特殊字符 clean_op = "".join(c if c.isalnum() else "_" for c in operation) timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") new_name = f"{name}_{clean_op}_{timestamp}{ext}" return os.path.join(self.get_desktop_path(), new_name) def save_csv_file(self, data, save_path): """保存CSV文件到指定路径""" try: with open(save_path, 'w', encoding='utf-8-sig', newline='') as file: writer = csv.writer(file) writer.writerows(data) # 更新文件信息显示 self.show_file_info(save_path) self.log_message(f"文件已保存到: {save_path}") return True except Exception as e: error_msg = f"保存文件时出错: {str(e)}" self.log_message(error_msg, "error") messagebox.showerror("错误", error_msg) return False def process_csv(self): """处理CSV文件(排序、去重等)并保存到桌面""" if not self.file_path.get(): messagebox.showwarning("警告", "请先选择CSV文件") return if not self.csv_data: messagebox.showwarning("警告", "CSV文件没有数据") return self.log_message("开始处理CSV文件...") new_data = [self.headers.copy()] data_rows = self.csv_data[1:] # 去重处理 if self.enable_dedupe.get(): try: dedupe_index = self.headers.index(self.dedupe_header.get()) seen = set() unique_rows = [] for row in data_rows: if len(row) > dedupe_index: key = row[dedupe_index] if key not in seen: seen.add(key) unique_rows.append(row) data_rows = unique_rows self.log_message(f"去重完成,根据表头 '{self.dedupe_header.get()}' 删除重复项") except Exception as e: self.log_message(f"去重时出错: {str(e)}", "error") messagebox.showerror("错误", f"去重时出错: {str(e)}") return # 排序处理 if self.enable_sort.get(): try: sort_index = self.headers.index(self.sort_header.get()) order = self.sort_order.get() reverse = (order == "降序") # 字母范围过滤 if self.enable_custom_letter_sort.get(): try: letter_start = self.letter_range_start.get().upper() letter_end = self.letter_range_end.get().upper() if not (len(letter_start) == 1 and len(letter_end) == 1 and letter_start.isalpha() and letter_end.isalpha()): raise ValueError("字母范围必须是单个字母(如A-Z)") filtered_rows = [] for row in data_rows: if len(row) > sort_index: value = str(row[sort_index]).strip().upper() if value and letter_start <= value[0] <= letter_end: filtered_rows.append(row) data_rows = filtered_rows self.log_message(f"字母范围过滤完成:{letter_start} 到 {letter_end}") except Exception as e: self.log_message(f"字母范围过滤失败: {str(e)}", "error") messagebox.showerror("错误", f"字母范围过滤失败: {str(e)}") return # 排序逻辑 def sort_key(row): if len(row) > sort_index: value = row[sort_index] # 尝试解析为日期 for fmt in ("%Y-%m-%d %H:%M:%S", "%Y-%m-%d", "%m/%d/%Y", "%Y.%m.%d"): try: return datetime.strptime(value, fmt) except ValueError: continue # 尝试解析为数字 try: return float(value) except ValueError: pass return value.lower() # 默认按字符串排序 return "" try: if order == "自定义字母排序": data_rows.sort(key=lambda x: str(sort_key(x)).lower() if len(x) > sort_index else "", reverse=False) else: data_rows.sort(key=sort_key, reverse=reverse) self.log_message(f"排序完成,表头 '{self.sort_header.get()}',顺序: {order}") except Exception as e: self.log_message(f"排序时出错: {str(e)}", "error") messagebox.showerror("错误", f"排序时出错: {str(e)}") return except Exception as e: self.log_message(f"排序处理时出错: {str(e)}", "error") messagebox.showerror("错误", f"排序处理时出错: {str(e)}") return # 组合最终数据 new_data.extend(data_rows) # 生成操作描述 operations = [] if self.enable_sort.get(): operations.append(f"sorted_{self.sort_header.get()}_{self.sort_order.get()}") if self.enable_dedupe.get(): operations.append(f"deduped_{self.dedupe_header.get()}") operation = "_".join(operations) if operations else "processed" # 生成保存路径 save_path = self.generate_filename(self.file_path.get(), operation) # 保存文件 if self.save_csv_file(new_data, save_path): # 更新当前数据 self.csv_data = new_data messagebox.showinfo("成功", f"文件处理完成,已保存到桌面:\n{os.path.basename(save_path)}") def merge_csv_files(self): """合并多个CSV文件并保存到桌面""" if not self.merge_file_paths: messagebox.showwarning("警告", "请先添加要合并的文件") return try: # 检查所有文件是否存在 missing_files = [f for f in self.merge_file_paths if not os.path.exists(f)] if missing_files: raise FileNotFoundError(f"以下文件不存在: {', '.join(missing_files)}") merge_column = self.merge_column.get() common_headers = None all_data = [] # 收集所有文件的表头和数据 header_sets = [] for file_path in self.merge_file_paths: with open(file_path, 'r', encoding='utf-8-sig') as file: reader = csv.reader(file) data = list(reader) if data: header_sets.append(set(data[0])) all_data.append(data) # 找出共同表头 if header_sets: common_headers = set(header_sets[0]) for headers in header_sets[1:]: common_headers.intersection_update(headers) common_headers = sorted(common_headers) if not common_headers: raise ValueError("选中的文件没有共同的列,无法合并") # 如果没有指定合并依据列,使用所有共同列 merge_indices = None if merge_column: if merge_column not in common_headers: raise ValueError(f"合并依据列 '{merge_column}' 不在共同列中") merge_indices = [i for i, h in enumerate(common_headers) if h == merge_column] # 合并数据 merged_data = [common_headers.copy()] key_counter = defaultdict(int) for data in all_data: if not data: continue headers = data[0] header_map = {h: i for i, h in enumerate(headers)} for row in data[1:]: # 如果指定了合并列,检查是否已存在相同键 if merge_indices: merge_values = [row[header_map[h]] for h in common_headers if h == merge_column] if merge_values: key = tuple(merge_values) key_counter[key] += 1 if key_counter[key] > 1: continue # 跳过重复键的行 # 构建新行,只保留共同列 new_row = [] for col in common_headers: if col in header_map and len(row) > header_map[col]: new_row.append(row[header_map[col]]) else: new_row.append("") merged_data.append(new_row) # 生成操作描述 operation = "merged" if merge_column: operation += f"_by_{merge_column}" # 生成保存路径 first_file = os.path.basename(self.merge_file_paths[0]) save_path = self.generate_filename(first_file, operation) # 保存文件 if self.save_csv_file(merged_data, save_path): messagebox.showinfo("成功", f"文件合并完成,已保存到桌面:\n{os.path.basename(save_path)}") except Exception as e: error_msg = f"合并文件时出错: {str(e)}" self.log_message(error_msg, "error") messagebox.showerror("错误", error_msg) if __name__ == "__main__": root = tk.Tk() app = CSVProcessorApp(root) root.mainloop() 优化这个代码,并新增以下功能 1.排序和去重功能中增加自定义指定某行为表头的功能 2.优化功能处理顺序,新增一个可以依次执行删除行,再排序,在去重的功能,比如处理一个csv数据,设置数据第二行为表头,然后删除某个关键字的所在行,在对这个数据进行指定列排序,比如升序,即整份数据都按照升序进行排列,最后最后在执行删除指定表头的重复项的功能,最后在桌面上输出一份处理后的新的csv数据。 3.并保留现在这个代码也可以单一执行某种功能的功能
07-10
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值