不是哥们你说话是人能说出来的吗?
Aurelia_Veil · · 科技·工程
不知道,反正思路是我想的,代码是 AI 的。
模式一:删除所有标点符号
删除所有标点符号,在旁人看来就是一个很有效率急的人,直接受收到同学和老师夸赞“何意味?”
注:不会对代码和 KaTeX 进行改变。
模式二:文字间添加句号
每个文字间添加句号,体现出你悠然自得,不紧不慢的优秀特点。
模式三:文本长度减半
每两个字删一个字,秒变文言文,轻松获取信息。
模式四:语序颠倒
俗话说,人类阅读文字顺序有错误也照样读,于是就有了这个模式。
快捷键说明
-
Alt+1/2/3/4/5:模式切换(第一个是正常状态)。 -
Alt+H:显示或隐藏控制框。
:::info[源代码]
// ==UserScript==
// @name 不是哥们你说话是人能说出来的吗?
// @namespace http://tampermonkey.net/
// @version 6.2
// @description 提供多种模式:删除标点符号、汉字之间添加句号、每两个汉字删一个汉字等
// @author Aurelia_Veil and Deepseek
// @match *://*/*
// @grant GM_registerMenuCommand
// @grant GM_setValue
// @grant GM_getValue
// ==/UserScript==
(function() {
'use strict';
// 模式定义
const MODES = {
NORMAL: 'normal', // 正常模式(不处理)
REMOVE_PUNCTUATION: 'remove', // 删除标点符号
ADD_DOTS_BETWEEN_CHINESE: 'add', // 汉字之间添加句号
REMOVE_ALTERNATE_CHINESE: 'removeAlt', // 每两个汉字删一个汉字
SWAP_FIRST_TWO_IN_TRIPLE: 'swap' // 每三个汉字交换前两个汉字(两个字则交换)
};
// 获取保存的模式,默认为正常模式
let currentMode = GM_getValue('punctuationMode', MODES.NORMAL);
// 获取控制框显示状态,默认为显示
let controlsVisible = GM_getValue('controlsVisible', true);
// 存储原始文本
const originalTextMap = new WeakMap();
// 控制框的ID
const CONTROLS_ID = 'punctuation-controls';
// 匹配中英文标点符号的正则表达式
const punctuationRegex = /[\u3000-\u303F\uFF00-\uFFEF\u2000-\u206F\u2E00-\u2E7F`~!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?~!@#¥%……&*()——+【】{}|;:'",。、?《》]/g;
// 匹配所有汉字
const allChineseRegex = /([\u4e00-\u9fa5]+)/g;
// 检查节点是否在控制框内
function isInControls(node) {
if (!node || !node.parentElement) return false;
// 获取控制框元素
const controls = document.getElementById(CONTROLS_ID);
if (!controls) return false;
// 检查节点是否在控制框内
return controls.contains(node.parentElement) || controls.contains(node);
}
// 检查节点是否在代码块、LaTeX或数学公式中
function isInCodeOrMath(node) {
if (!node || !node.parentElement) return false;
// 检查父元素或祖先元素是否是代码块、数学公式等
let parent = node.parentElement;
let depth = 0;
const maxDepth = 10; // 防止无限循环
while (parent && depth < maxDepth) {
const tagName = parent.tagName.toLowerCase();
const className = parent.className || '';
const id = parent.id || '';
// 检查是否是代码相关元素
if (tagName === 'code' || tagName === 'pre' ||
tagName === 'script' || tagName === 'style' ||
tagName === 'textarea' || tagName === 'input') {
return true;
}
// 检查类名或ID中是否包含代码/数学相关关键词
const codeMathKeywords = [
'code', 'pre', 'math', 'latex', 'equation', 'formula',
'katex', 'mathjax', 'hljs', 'highlight', 'syntax',
'program', 'coder', 'coding', 'algorithm'
];
const combinedText = (className + ' ' + id).toLowerCase();
for (const keyword of codeMathKeywords) {
if (combinedText.includes(keyword)) {
return true;
}
}
// 检查是否是数学公式元素
if (tagName === 'math' ||
parent.getAttribute('data-math') ||
parent.getAttribute('data-latex') ||
parent.getAttribute('data-formula')) {
return true;
}
parent = parent.parentElement;
depth++;
}
return false;
}
// 保存文本节点的原始内容(强制保存,确保有备份)
function saveOriginalText(node, text) {
// 如果节点在控制框内或代码/数学公式中,不保存
if (isInControls(node) || isInCodeOrMath(node)) return;
// 总是保存最新的原始文本,确保有备份
originalTextMap.set(node, text);
}
// 获取文本节点的原始内容
function getOriginalText(node) {
// 如果WeakMap中有,返回保存的原始文本
if (originalTextMap.has(node)) {
return originalTextMap.get(node);
}
// 否则返回当前文本内容
return node.textContent;
}
// 处理单个文本节点
function processNode(node) {
// 跳过控制框内或代码/数学公式中的节点
if (isInControls(node) || isInCodeOrMath(node)) return;
if (node.nodeType !== Node.TEXT_NODE || node.textContent.trim() === "") {
return;
}
// 保存原始文本(确保有备份)
const currentText = node.textContent;
if (!originalTextMap.has(node)) {
saveOriginalText(node, currentText);
}
// 获取原始文本
const originalText = getOriginalText(node);
let newText = originalText;
if (currentMode === MODES.REMOVE_PUNCTUATION) {
// 模式1: 删除所有标点符号
newText = originalText.replace(punctuationRegex, '');
} else if (currentMode === MODES.ADD_DOTS_BETWEEN_CHINESE) {
// 模式2: 在每个汉字之间添加句号
newText = originalText.replace(allChineseRegex, (match) => {
// 将连续的汉字转换为单个汉字之间加句号
return match.split('').join('。');
});
} else if (currentMode === MODES.REMOVE_ALTERNATE_CHINESE) {
// 模式3: 每两个汉字删一个汉字
newText = originalText.replace(allChineseRegex, (match) => {
const chars = match.split('');
const filteredChars = [];
for (let i = 0; i < chars.length; i++) {
// 保留第1、3、5...个汉字
if (i % 2 === 0) {
filteredChars.push(chars[i]);
}
}
return filteredChars.join('');
});
} else if (currentMode === MODES.SWAP_FIRST_TWO_IN_TRIPLE) {
// 模式5: 每三个汉字交换前两个汉字(如果只有两个字则交换这两个字)
newText = originalText.replace(allChineseRegex, (match) => {
const chars = match.split('');
const resultChars = [];
// 三个一组处理汉字
for (let i = 0; i < chars.length; i += 3) {
const group = chars.slice(i, i + 3);
if (group.length === 3) {
// 交换前两个汉字的位置
resultChars.push(group[1], group[0], group[2]);
} else if (group.length === 2) {
// 只有两个字,交换这两个字
resultChars.push(group[1], group[0]);
} else if (group.length === 1) {
// 只有一个字,保持不变
resultChars.push(group[0]);
}
}
return resultChars.join('');
});
}
// 如果文本有变化,则更新
if (node.textContent !== newText) {
// 再次保存原始文本,确保有备份
if (!originalTextMap.has(node) || originalTextMap.get(node) === node.textContent) {
saveOriginalText(node, originalText);
}
node.textContent = newText;
}
}
// 恢复单个文本节点到原始状态
function restoreNode(node) {
// 跳过控制框内或代码/数学公式中的节点
if (isInControls(node) || isInCodeOrMath(node)) return;
if (node.nodeType !== Node.TEXT_NODE) {
return;
}
const originalText = getOriginalText(node);
if (originalText && node.textContent !== originalText) {
node.textContent = originalText;
}
}
// 遍历DOM树中的所有文本节点
function walk(root, action) {
const walker = document.createTreeWalker(
root,
NodeFilter.SHOW_TEXT,
{
acceptNode: function(node) {
// 跳过控制框内或代码/数学公式中的节点
if (isInControls(node) || isInCodeOrMath(node)) {
return NodeFilter.FILTER_REJECT;
}
// 跳过脚本和样式标签中的内容
if (node.parentElement &&
(node.parentElement.tagName === 'SCRIPT' ||
node.parentElement.tagName === 'STYLE' ||
node.parentElement.tagName === 'NOSCRIPT' ||
node.parentElement.tagName === 'IFRAME')) {
return NodeFilter.FILTER_REJECT;
}
// 如果文本为空或只有空白,跳过
if (node.textContent.trim() === "") {
return NodeFilter.FILTER_REJECT;
}
return NodeFilter.FILTER_ACCEPT;
}
},
false
);
let node;
while ((node = walker.nextNode())) {
// 保存原始文本(确保每个节点都有备份)
if (!originalTextMap.has(node)) {
saveOriginalText(node, node.textContent);
}
// 执行指定操作
action(node);
}
}
// 切换模式并重新处理页面
function switchMode(mode) {
if (currentMode === mode) return;
// 保存当前状态
const previousMode = currentMode;
// 设置新模式
currentMode = mode;
GM_setValue('punctuationMode', mode);
// 如果从非正常模式切换到正常模式,恢复所有文本
if (previousMode !== MODES.NORMAL && mode === MODES.NORMAL) {
walk(document.body, restoreNode);
console.log('已切换到正常模式,已恢复所有文本');
updateModeButtons();
return;
}
// 如果从正常模式切换到其他模式,先确保有原始文本备份
if (previousMode === MODES.NORMAL) {
// 先确保所有节点都有原始文本备份
walk(document.body, (node) => {
if (!originalTextMap.has(node)) {
saveOriginalText(node, node.textContent);
}
});
}
// 如果切换到正常模式,只恢复不处理
if (mode === MODES.NORMAL) {
console.log('已切换到正常模式');
updateModeButtons();
return;
}
// 应用新处理模式
walk(document.body, processNode);
updateModeButtons();
console.log(`已切换到模式: ${getModeName(mode)}`);
}
// 获取模式名称
function getModeName(mode) {
switch(mode) {
case MODES.NORMAL: return '你终于正常说话了!';
case MODES.REMOVE_PUNCTUATION: return '你说话很急吗?';
case MODES.ADD_DOTS_BETWEEN_CHINESE: return '你说话磕巴吗?';
case MODES.REMOVE_ALTERNATE_CHINESE: return '你在概括吗?';
case MODES.SWAP_FIRST_TWO_IN_TRIPLE: return '你语序是正常的吗?';
default: return '未知模式';
}
}
// 更新模式按钮状态
function updateModeButtons() {
const controls = document.getElementById(CONTROLS_ID);
if (!controls) return;
const buttons = controls.querySelectorAll('.punctuation-btn');
buttons.forEach(btn => {
btn.classList.remove('active');
if (btn.dataset.mode === currentMode) {
btn.classList.add('active');
}
});
const statusText = controls.querySelector('.mode-status');
if (statusText) {
statusText.textContent = `当前: ${getModeName(currentMode)}`;
}
}
// 显示控制框
function showControls() {
controlsVisible = true;
GM_setValue('controlsVisible', true);
const controls = document.getElementById(CONTROLS_ID);
if (controls) {
controls.style.display = '';
console.log('控制框已显示');
} else {
createModeSwitchUI();
}
}
// 隐藏控制框
function hideControls() {
controlsVisible = false;
GM_setValue('controlsVisible', false);
const controls = document.getElementById(CONTROLS_ID);
if (controls) {
controls.style.display = 'none';
console.log('控制框已隐藏');
}
}
// 切换控制框显示状态
function toggleControls() {
if (controlsVisible) {
hideControls();
} else {
showControls();
}
}
// 创建模式切换按钮
function createModeSwitchUI() {
// 如果已经存在控制面板,先移除
const existingControls = document.getElementById(CONTROLS_ID);
if (existingControls) {
existingControls.remove();
}
// 创建样式
const style = document.createElement('style');
style.id = 'punctuation-controls-style';
style.textContent = `
#${CONTROLS_ID} {
position: fixed;
top: 20px;
right: 20px;
z-index: 2147483647;
background: rgba(0, 0, 0, 0.9);
color: white;
padding: 15px;
border-radius: 10px;
font-family: "Microsoft YaHei", Arial, sans-serif;
font-size: 12px;
box-shadow: 0 4px 20px rgba(0,0,0,0.4);
backdrop-filter: blur(10px);
border: 1px solid rgba(255,255,255,0.2);
min-width: 220px;
max-width: 250px;
user-select: none;
transform: translateZ(0);
}
#${CONTROLS_ID} h3 {
margin: 0 0 12px 0;
font-size: 14px;
text-align: center;
border-bottom: 1px solid rgba(255,255,255,0.3);
padding-bottom: 10px;
color: #4fc3f7;
}
.punctuation-btn {
background: #555;
color: white;
border: none;
padding: 8px 12px;
margin: 5px 0;
border-radius: 6px;
cursor: pointer;
font-size: 12px;
width: 100%;
transition: all 0.2s ease;
text-align: left;
position: relative;
overflow: hidden;
word-break: break-word;
white-space: normal;
line-height: 1.4;
min-height: 40px;
display: flex;
align-items: center;
}
.punctuation-btn:hover {
background: #666;
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(0,0,0,0.2);
}
.punctuation-btn.active {
background: linear-gradient(135deg, #2196F3, #21CBF3);
font-weight: bold;
padding-left: 25px;
}
.punctuation-btn.active::before {
content: "✓";
position: absolute;
left: 8px;
top: 50%;
transform: translateY(-50%);
font-weight: bold;
}
.mode-status {
margin-top: 12px;
font-size: 11px;
color: #aaa;
text-align: center;
padding-top: 8px;
border-top: 1px solid rgba(255,255,255,0.1);
}
.shortcut-info {
margin-top: 8px;
font-size: 10px;
color: #888;
text-align: center;
}
#${CONTROLS_ID}.dragging {
opacity: 0.9;
cursor: grabbing;
}
.close-btn {
position: absolute;
top: 5px;
right: 8px;
background: transparent;
border: none;
color: #aaa;
font-size: 16px;
cursor: pointer;
padding: 0;
width: 20px;
height: 20px;
line-height: 20px;
text-align: center;
border-radius: 50%;
}
.close-btn:hover {
background: rgba(255,255,255,0.1);
color: white;
}
`;
// 确保样式只添加一次
if (!document.getElementById('punctuation-controls-style')) {
document.head.appendChild(style);
}
// 创建控制面板
const controls = document.createElement('div');
controls.id = CONTROLS_ID;
controls.innerHTML = `
<button class="close-btn" title="关闭">×</button>
<h3>不是哥们你说话是人能说出来的吗?</h3>
<button class="punctuation-btn ${currentMode === MODES.NORMAL ? 'active' : ''}"
data-mode="${MODES.NORMAL}">
你终于正常说话了!
</button>
<button class="punctuation-btn ${currentMode === MODES.REMOVE_PUNCTUATION ? 'active' : ''}"
data-mode="${MODES.REMOVE_PUNCTUATION}">
你说话很急吗?
</button>
<button class="punctuation-btn ${currentMode === MODES.ADD_DOTS_BETWEEN_CHINESE ? 'active' : ''}"
data-mode="${MODES.ADD_DOTS_BETWEEN_CHINESE}">
你说话磕巴吗?
</button>
<button class="punctuation-btn ${currentMode === MODES.REMOVE_ALTERNATE_CHINESE ? 'active' : ''}"
data-mode="${MODES.REMOVE_ALTERNATE_CHINESE}">
你在概括吗?
</button>
<button class="punctuation-btn ${currentMode === MODES.SWAP_FIRST_TWO_IN_TRIPLE ? 'active' : ''}"
data-mode="${MODES.SWAP_FIRST_TWO_IN_TRIPLE}">
你语序是正常的吗?
</button>
<div class="mode-status">当前: ${getModeName(currentMode)}</div>
<div class="shortcut-info">快捷键: Alt+1/2/3/4/5/H</div>
`;
document.body.appendChild(controls);
// 初始显示状态
if (!controlsVisible) {
controls.style.display = 'none';
}
// 添加事件监听器
controls.querySelectorAll('.punctuation-btn').forEach(btn => {
btn.addEventListener('click', (e) => {
if (e.target.classList.contains('close-btn')) return;
const mode = e.target.dataset.mode;
switchMode(mode);
});
});
// 关闭按钮事件 - 改为隐藏而不是移除
controls.querySelector('.close-btn').addEventListener('click', (e) => {
e.preventDefault();
hideControls();
});
// 添加拖动功能
let isDragging = false;
let dragOffsetX, dragOffsetY;
controls.addEventListener('mousedown', (e) => {
if (e.target.tagName === 'BUTTON' && !e.target.classList.contains('close-btn')) {
return;
}
isDragging = true;
const rect = controls.getBoundingClientRect();
dragOffsetX = e.clientX - rect.left;
dragOffsetY = e.clientY - rect.top;
controls.classList.add('dragging');
controls.style.cursor = 'grabbing';
});
document.addEventListener('mousemove', (e) => {
if (!isDragging) return;
controls.style.left = (e.clientX - dragOffsetX) + 'px';
controls.style.top = (e.clientY - dragOffsetY) + 'px';
controls.style.right = 'auto';
});
document.addEventListener('mouseup', () => {
if (isDragging) {
isDragging = false;
controls.classList.remove('dragging');
controls.style.cursor = '';
}
});
}
// 注册油猴菜单命令
if (typeof GM_registerMenuCommand !== 'undefined') {
GM_registerMenuCommand('切换到正常模式', () => switchMode(MODES.NORMAL));
GM_registerMenuCommand('切换到删除标点模式', () => switchMode(MODES.REMOVE_PUNCTUATION));
GM_registerMenuCommand('切换到汉字加句号模式', () => switchMode(MODES.ADD_DOTS_BETWEEN_CHINESE));
GM_registerMenuCommand('切换到每两个汉字删一个模式', () => switchMode(MODES.REMOVE_ALTERNATE_CHINESE));
GM_registerMenuCommand('切换到每三个汉字交换前两个模式', () => switchMode(MODES.SWAP_FIRST_TWO_IN_TRIPLE));
GM_registerMenuCommand('显示控制面板', () => showControls());
GM_registerMenuCommand('隐藏控制面板', () => hideControls());
GM_registerMenuCommand('切换控制面板显示', () => toggleControls());
GM_registerMenuCommand('重新备份所有文本', () => {
walk(document.body, (node) => {
if (!originalTextMap.has(node)) {
saveOriginalText(node, node.textContent);
}
});
console.log('已重新备份所有文本');
});
}
// 使用MutationObserver监听DOM变化
const observer = new MutationObserver((mutations) => {
if (currentMode === MODES.NORMAL) return;
mutations.forEach((mutation) => {
mutation.addedNodes.forEach((node) => {
if (node.nodeType === Node.TEXT_NODE) {
// 跳过控制框内或代码/数学公式中的节点
if (!isInControls(node) && !isInCodeOrMath(node)) {
processNode(node);
}
} else if (node.nodeType === Node.ELEMENT_NODE) {
// 跳过控制框元素本身
if (node.id === CONTROLS_ID || isInControls(node) || isInCodeOrMath(node)) {
return;
}
// 处理新增元素中的文本节点
setTimeout(() => {
walk(node, (textNode) => {
processNode(textNode);
});
}, 0);
}
});
});
});
// 初始化函数
function init() {
console.log('网页标点处理工具初始化...');
console.log(`控制框显示状态: ${controlsVisible ? '显示' : '隐藏'}`);
console.log(`当前模式: ${getModeName(currentMode)}`);
// 创建UI控制面板(延迟执行,确保页面完全加载)
setTimeout(() => {
try {
createModeSwitchUI();
console.log('控制面板创建成功');
} catch (error) {
console.error('创建控制面板失败:', error);
}
}, 1000);
// 如果不是正常模式,处理初始页面
if (currentMode !== MODES.NORMAL) {
setTimeout(() => {
// 先确保所有文本节点都有备份
walk(document.body, (node) => {
if (!originalTextMap.has(node)) {
saveOriginalText(node, node.textContent);
}
});
// 然后处理页面
walk(document.body, (node) => {
processNode(node);
});
}, 500);
} else {
// 正常模式下也确保有备份
setTimeout(() => {
walk(document.body, (node) => {
if (!originalTextMap.has(node)) {
saveOriginalText(node, node.textContent);
}
});
}, 500);
}
// 开始监听DOM变化
observer.observe(document.body, {
childList: true,
subtree: true
});
console.log('网页标点处理工具已加载');
}
// 等待页面加载完成
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
// 延迟初始化,确保页面完全加载
setTimeout(init, 500);
}
// 添加快捷键支持
document.addEventListener('keydown', (e) => {
// 检查是否是输入元素,如果是则不触发快捷键
const activeElement = document.activeElement;
const isInputElement = activeElement && (
activeElement.tagName === 'INPUT' ||
activeElement.tagName === 'TEXTAREA' ||
activeElement.tagName === 'SELECT' ||
activeElement.contentEditable === 'true'
);
if (isInputElement) {
return; // 在输入元素中不触发快捷键
}
// Alt+1: 正常模式
if (e.altKey && (e.key === '1' || e.key === 'Digit1')) {
e.preventDefault();
switchMode(MODES.NORMAL);
}
// Alt+2: 删除标点模式
else if (e.altKey && (e.key === '2' || e.key === 'Digit2')) {
e.preventDefault();
switchMode(MODES.REMOVE_PUNCTUATION);
}
// Alt+3: 汉字加句号模式
else if (e.altKey && (e.key === '3' || e.key === 'Digit3')) {
e.preventDefault();
switchMode(MODES.ADD_DOTS_BETWEEN_CHINESE);
}
// Alt+4: 每两个汉字删一个模式
else if (e.altKey && (e.key === '4' || e.key === 'Digit4')) {
e.preventDefault();
switchMode(MODES.REMOVE_ALTERNATE_CHINESE);
}
// Alt+5: 每三个汉字交换前两个模式
else if (e.altKey && (e.key === '5' || e.key === 'Digit5')) {
e.preventDefault();
switchMode(MODES.SWAP_FIRST_TWO_IN_TRIPLE);
}
// Alt+H: 切换控制框显示/隐藏
else if (e.altKey && (e.key === 'h' || e.key === 'H')) {
e.preventDefault();
toggleControls();
}
// Alt+R: 重新备份所有文本(调试用)
else if (e.altKey && (e.key === 'r' || e.key === 'R')) {
e.preventDefault();
walk(document.body, (node) => {
if (!originalTextMap.has(node)) {
saveOriginalText(node, node.textContent);
}
});
console.log('已重新备份所有文本');
}
});
// 将函数暴露给控制台,便于调试
window.punctuationTool = {
switchToNormal: () => switchMode(MODES.NORMAL),
switchToRemove: () => switchMode(MODES.REMOVE_PUNCTUATION),
switchToAdd: () => switchMode(MODES.ADD_DOTS_BETWEEN_CHINESE),
switchToRemoveAlt: () => switchMode(MODES.REMOVE_ALTERNATE_CHINESE),
switchToSwap: () => switchMode(MODES.SWAP_FIRST_TWO_IN_TRIPLE),
showControls: () => showControls(),
hideControls: () => hideControls(),
toggleControls: () => toggleControls(),
getCurrentMode: () => currentMode,
getControlsVisible: () => controlsVisible,
reprocess: () => {
if (currentMode !== MODES.NORMAL) {
walk(document.body, (node) => {
processNode(node);
});
}
},
backupAllText: () => {
walk(document.body, (node) => {
if (!originalTextMap.has(node)) {
saveOriginalText(node, node.textContent);
}
});
console.log('已备份所有文本');
},
restoreAllText: () => {
walk(document.body, (node) => {
restoreNode(node);
});
console.log('已恢复所有文本');
},
// 调试函数:检查节点是否在控制框内
isInControls: (node) => isInControls(node),
// 调试函数:检查节点是否在代码/数学公式中
isInCodeOrMath: (node) => isInCodeOrMath(node)
};
})();
:::
点个赞关个注谢谢了!