"""内容格式化器 - 适配不同平台的格式要求""" import re class ContentFormatter: """内容格式化器:将Markdown内容转换为目标平台的最佳格式""" def format_for_platform(self, content: str, platform: str) -> str: """将Markdown内容转换为目标平台的最佳格式""" formatter = getattr(self, f"_format_{platform}", self._format_default) return formatter(content) def _format_wechat(self, content: str) -> str: """微信公众号格式:去外链、段落加粗关键句""" result = content # 移除外部链接,保留文本 result = re.sub( r"\[([^\]]+)\]\((?!https?://mp\.weixin\.qq\.com|https?://wx\.qq\.com|weixin://)(?:[^)]+)\)", r"\1", result, ) # 将Markdown标题转为HTML(公众号支持HTML) result = re.sub(r"^### (.+)$", r"

\1

", result, flags=re.MULTILINE) result = re.sub(r"^## (.+)$", r"

\1

", result, flags=re.MULTILINE) result = re.sub(r"^# (.+)$", r"

\1

", result, flags=re.MULTILINE) # 加粗关键句:将 **text** 转为 text result = re.sub(r"\*\*([^*]+)\*\*", r"\1", result) # 图片保留(公众号支持) # result = re.sub(r"!\[([^\]]*)\]\([^)]+\)", r"[图片:\1]", result) # 代码块处理 result = re.sub(r"```(\w*)\n", r"
", result)
        result = re.sub(r"```", "
", result) # 行内代码 result = re.sub(r"`([^`]+)`", r"\1", result) # 段落分隔:双换行 -> 段落 result = re.sub(r"\n\n+", "\n\n", result) return result.strip() def _format_xiaohongshu(self, content: str) -> str: """小红书格式:短句、emoji、话题标签""" result = content # 移除所有Markdown标记 result = self._strip_markdown(result) # 长句拆分为短句 result = self._split_long_sentences(result) # 添加分段emoji(在段落间插入) result = self._add_paragraph_emojis(result) # 提取并移动话题标签到文末 tags = re.findall(r"#(\S+)", result) result = re.sub(r"#\S+\s*", "", result) # 重新添加标签到文末 if tags: deduped_tags = list(dict.fromkeys(tags))[:8] tag_line = " ".join(f"#{t}" for t in deduped_tags) result = result.strip() + "\n\n" + tag_line return result.strip() def _format_zhihu(self, content: str) -> str: """知乎格式:保留Markdown、添加引用标注""" result = content # 知乎支持Markdown,基本保留 # 为引用内容添加标注 result = re.sub( r"(^|\n)(据|根据|参考|来源)[::]?\s*", r"\1> ", result, ) # 确保代码块格式正确 # 将不含语言标识的代码块加上默认标识 result = re.sub(r"```\n", "```text\n", result) # 图片链接转为知乎兼容格式 # result保持原样,知乎编辑器会处理 return result.strip() def _format_baijiahao(self, content: str) -> str: """百家号格式:转为HTML、结构化小标题""" result = content # 标题转HTML result = re.sub(r"^### (.+)$", r"

\1

", result, flags=re.MULTILINE) result = re.sub(r"^## (.+)$", r"

\1

", result, flags=re.MULTILINE) result = re.sub(r"^# (.+)$", r"

\1

", result, flags=re.MULTILINE) # 加粗 result = re.sub(r"\*\*([^*]+)\*\*", r"\1", result) # 移除代码块(百家号不支持) result = re.sub(r"```[\s\S]*?```", self._code_block_to_text, result) # 行内代码移除反引号 result = re.sub(r"`([^`]+)`", r"\1", result) # 链接保留文本 result = re.sub(r"\[([^\]]+)\]\([^)]+\)", r"\1", result) return result.strip() def _format_douyin(self, content: str) -> str: """抖音格式:纯文本+emoji,极简""" result = self._strip_markdown(content) # 限制长度(抖音文案建议简短) if len(result) > 500: # 取前500字,在句号处截断 truncated = result[:500] last_period = max( truncated.rfind("。"), truncated.rfind("!"), truncated.rfind("?"), ) if last_period > 200: result = truncated[: last_period + 1] else: result = truncated return result.strip() def _format_toutiao(self, content: str) -> str: """今日头条格式:HTML+结构化""" result = content # 标题转HTML result = re.sub(r"^### (.+)$", r"

\1

", result, flags=re.MULTILINE) result = re.sub(r"^## (.+)$", r"

\1

", result, flags=re.MULTILINE) result = re.sub(r"^# (.+)$", r"

\1

", result, flags=re.MULTILINE) # 加粗 result = re.sub(r"\*\*([^*]+)\*\*", r"\1", result) # 移除代码块 result = re.sub(r"```[\s\S]*?```", self._code_block_to_text, result) result = re.sub(r"`([^`]+)`", r"\1", result) # 链接保留文本 result = re.sub(r"\[([^\]]+)\]\([^)]+\)", r"\1", result) return result.strip() def _format_default(self, content: str) -> str: """默认格式:清理Markdown为纯文本""" return self._strip_markdown(content).strip() # --- 辅助方法 --- @staticmethod def _strip_markdown(text: str) -> str: """清理所有Markdown标记为纯文本""" result = text # 移除代码块 result = re.sub(r"```[\s\S]*?```", ContentFormatter._code_block_to_text, result) # 移除行内代码 result = re.sub(r"`([^`]+)`", r"\1", result) # 移除图片,保留alt result = re.sub(r"!\[([^\]]*)\]\([^)]+\)", r"[\1]", result) # 移除链接,保留文本 result = re.sub(r"\[([^\]]+)\]\([^)]+\)", r"\1", result) # 移除加粗/斜体 result = re.sub(r"\*\*\*([^*]+)\*\*\*", r"\1", result) result = re.sub(r"\*\*([^*]+)\*\*", r"\1", result) result = re.sub(r"\*([^*]+)\*", r"\1", result) # 移除标题标记 result = re.sub(r"^#{1,6}\s+", "", result, flags=re.MULTILINE) # 移除引用标记 result = re.sub(r"^>\s+", "", result, flags=re.MULTILINE) # 移除水平线 result = re.sub(r"^---+$", "", result, flags=re.MULTILINE) # 移除列表标记 result = re.sub(r"^[\s]*[-*+]\s+", "", result, flags=re.MULTILINE) result = re.compile(r"^[\s]*\d+\.\s+", flags=re.MULTILINE).sub("", result) return result @staticmethod def _code_block_to_text(match: re.Match | str) -> str: """将代码块匹配转为纯文本""" if isinstance(match, re.Match): text = match.group(0) else: text = match # 移除代码围栏,保留内容 text = re.sub(r"^```\w*\n?", "", text) text = re.sub(r"\n?```$", "", text) return text.strip() @staticmethod def _split_long_sentences(text: str) -> str: """将长句拆分为短句""" result = text # 在句号后如果跟长文本,插入换行 result = re.sub(r"([。!?])", r"\1\n", result) # 清理多余换行 result = re.sub(r"\n{3,}", "\n\n", result) return result @staticmethod def _add_paragraph_emojis(text: str) -> str: """在段落间添加emoji(小红书风格)""" emojis = ["✨", "💡", "📌", "🔥", "⭐", "🎯", "💪", "🌟"] lines = text.split("\n") result: list[str] = [] emoji_idx = 0 for i, line in enumerate(lines): stripped = line.strip() if not stripped: if result and result[-1].strip(): result.append("") continue # 每隔几段添加emoji if i > 0 and stripped and not stripped.startswith("#") and emoji_idx < len(emojis): if result and result[-1].strip() == "": result.append(f"{emojis[emoji_idx]} {stripped}") emoji_idx += 1 else: result.append(stripped) else: result.append(stripped) return "\n".join(result)