text_space_stripper 文本去空格换行
This commit is contained in:
@@ -0,0 +1,285 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
import { faCopy, faCheck, faTrash, faEraser, faPlay } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import ToolHeader from '@/components/ToolHeader';
|
||||||
|
import { useLanguage } from '@/context/LanguageContext';
|
||||||
|
|
||||||
|
// 添加CSS变量样式
|
||||||
|
const styles = {
|
||||||
|
card: "card p-6",
|
||||||
|
input: "search-input w-full",
|
||||||
|
textarea: "w-full p-3 bg-block border border-purple-glow rounded-lg text-primary focus:border-[#6366F1] focus:outline-none focus:ring-1 focus:ring-[#6366F1] transition-all resize-none",
|
||||||
|
label: "text-sm text-secondary font-medium mb-1",
|
||||||
|
secondaryText: "text-sm text-tertiary",
|
||||||
|
button: "text-left w-full px-3 py-2 rounded-md text-sm text-secondary hover:bg-block-hover transition-colors",
|
||||||
|
radioGroup: "flex flex-col sm:flex-row gap-3",
|
||||||
|
radioItem: "relative flex-1",
|
||||||
|
radioInput: "absolute opacity-0 w-full h-full cursor-pointer",
|
||||||
|
radioLabel: "block w-full px-4 py-2 text-center text-sm rounded-md border border-purple-glow/30 cursor-pointer hover:bg-block-hover transition-all",
|
||||||
|
radioActive: "bg-gradient-to-r from-[#6366F1] to-[#8B5CF6] text-white border-transparent shadow-md shadow-[#6366F1]/20",
|
||||||
|
iconButton: "text-tertiary hover:text-purple transition-colors",
|
||||||
|
}
|
||||||
|
|
||||||
|
// 去空格模式类型
|
||||||
|
type StripMode = 'both' | 'start' | 'end' | 'all' | 'newlines' | 'all_and_newlines';
|
||||||
|
|
||||||
|
export default function TextSpaceStripper() {
|
||||||
|
const { t } = useLanguage();
|
||||||
|
|
||||||
|
// 输入文本
|
||||||
|
const [inputText, setInputText] = useState('');
|
||||||
|
// 输出文本
|
||||||
|
const [outputText, setOutputText] = useState('');
|
||||||
|
// 去除模式
|
||||||
|
const [stripMode, setStripMode] = useState<StripMode>('both');
|
||||||
|
// 复制状态
|
||||||
|
const [copied, setCopied] = useState(false);
|
||||||
|
|
||||||
|
// 清空输入
|
||||||
|
const clearText = () => {
|
||||||
|
setInputText('');
|
||||||
|
setOutputText('');
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理文本
|
||||||
|
const processText = () => {
|
||||||
|
if (!inputText) return;
|
||||||
|
|
||||||
|
let result = inputText;
|
||||||
|
|
||||||
|
switch (stripMode) {
|
||||||
|
case 'both':
|
||||||
|
result = inputText.trim();
|
||||||
|
break;
|
||||||
|
case 'start':
|
||||||
|
result = inputText.replace(/^\s+/, '');
|
||||||
|
break;
|
||||||
|
case 'end':
|
||||||
|
result = inputText.replace(/\s+$/, '');
|
||||||
|
break;
|
||||||
|
case 'all':
|
||||||
|
result = inputText.replace(/\s+/g, '');
|
||||||
|
break;
|
||||||
|
case 'newlines':
|
||||||
|
result = inputText.replace(/[\r\n]+/g, '');
|
||||||
|
break;
|
||||||
|
case 'all_and_newlines':
|
||||||
|
// 先去除所有换行符,再去除所有空格
|
||||||
|
result = inputText.replace(/[\r\n]+/g, ' ').replace(/\s+/g, '');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
setOutputText(result);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 复制结果
|
||||||
|
const copyResult = () => {
|
||||||
|
if (!outputText) return;
|
||||||
|
|
||||||
|
navigator.clipboard.writeText(outputText)
|
||||||
|
.then(() => {
|
||||||
|
setCopied(true);
|
||||||
|
setTimeout(() => setCopied(false), 2000);
|
||||||
|
})
|
||||||
|
.catch(err => console.error(t('tools.text_space_stripper.copy_failed'), err));
|
||||||
|
};
|
||||||
|
|
||||||
|
// 加载示例
|
||||||
|
const loadExample = () => {
|
||||||
|
setInputText(' 这是一个 带有多余空格 和换行符的文本示例。\n\n这是 第二行 内容。\n 还有第三行内容。 \n');
|
||||||
|
setOutputText('');
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen flex flex-col max-w-[1440px] mx-auto p-4 md:p-6">
|
||||||
|
<ToolHeader
|
||||||
|
toolCode="text_space_stripper"
|
||||||
|
icon={faEraser}
|
||||||
|
title=""
|
||||||
|
description=""
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* 主内容区 */}
|
||||||
|
<div className="grid grid-cols-1 lg:grid-cols-12 gap-6">
|
||||||
|
{/* 左侧 - 输入和设置 */}
|
||||||
|
<div className="lg:col-span-6 space-y-6">
|
||||||
|
{/* 输入区域 */}
|
||||||
|
<div className={styles.card}>
|
||||||
|
<h2 className="text-md font-medium text-primary mb-4">{t('tools.text_space_stripper.input_text')}</h2>
|
||||||
|
<textarea
|
||||||
|
value={inputText}
|
||||||
|
onChange={(e) => setInputText(e.target.value)}
|
||||||
|
placeholder={t('tools.text_space_stripper.input_placeholder')}
|
||||||
|
className={styles.textarea}
|
||||||
|
rows={10}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="flex justify-end gap-2 mt-4">
|
||||||
|
<button
|
||||||
|
className="btn-secondary"
|
||||||
|
onClick={clearText}
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon icon={faTrash} className="mr-2" />
|
||||||
|
{t('tools.text_space_stripper.clear')}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="btn-primary"
|
||||||
|
onClick={processText}
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon icon={faPlay} className="mr-2" />
|
||||||
|
{t('tools.text_space_stripper.process')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 工具选项 */}
|
||||||
|
<div className={styles.card}>
|
||||||
|
<h2 className="text-md font-medium text-primary mb-4">{t('tools.text_space_stripper.tool_options')}</h2>
|
||||||
|
|
||||||
|
<div className="space-y-4">
|
||||||
|
{/* 去除方式 */}
|
||||||
|
<div>
|
||||||
|
<p className={styles.label}>{t('tools.text_space_stripper.strip_mode')}</p>
|
||||||
|
<div className={styles.radioGroup}>
|
||||||
|
<div className={styles.radioItem}>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
id="both"
|
||||||
|
className={styles.radioInput}
|
||||||
|
checked={stripMode === 'both'}
|
||||||
|
onChange={() => setStripMode('both')}
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
htmlFor="both"
|
||||||
|
className={`${styles.radioLabel} ${stripMode === 'both' ? styles.radioActive : ''}`}
|
||||||
|
>
|
||||||
|
{t('tools.text_space_stripper.strip_mode_both')}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.radioItem}>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
id="start"
|
||||||
|
className={styles.radioInput}
|
||||||
|
checked={stripMode === 'start'}
|
||||||
|
onChange={() => setStripMode('start')}
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
htmlFor="start"
|
||||||
|
className={`${styles.radioLabel} ${stripMode === 'start' ? styles.radioActive : ''}`}
|
||||||
|
>
|
||||||
|
{t('tools.text_space_stripper.strip_mode_start')}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.radioItem}>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
id="end"
|
||||||
|
className={styles.radioInput}
|
||||||
|
checked={stripMode === 'end'}
|
||||||
|
onChange={() => setStripMode('end')}
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
htmlFor="end"
|
||||||
|
className={`${styles.radioLabel} ${stripMode === 'end' ? styles.radioActive : ''}`}
|
||||||
|
>
|
||||||
|
{t('tools.text_space_stripper.strip_mode_end')}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={`${styles.radioGroup} mt-3`}>
|
||||||
|
<div className={styles.radioItem}>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
id="all"
|
||||||
|
className={styles.radioInput}
|
||||||
|
checked={stripMode === 'all'}
|
||||||
|
onChange={() => setStripMode('all')}
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
htmlFor="all"
|
||||||
|
className={`${styles.radioLabel} ${stripMode === 'all' ? styles.radioActive : ''}`}
|
||||||
|
>
|
||||||
|
{t('tools.text_space_stripper.strip_mode_all')}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.radioItem}>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
id="newlines"
|
||||||
|
className={styles.radioInput}
|
||||||
|
checked={stripMode === 'newlines'}
|
||||||
|
onChange={() => setStripMode('newlines')}
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
htmlFor="newlines"
|
||||||
|
className={`${styles.radioLabel} ${stripMode === 'newlines' ? styles.radioActive : ''}`}
|
||||||
|
>
|
||||||
|
{t('tools.text_space_stripper.strip_mode_newlines')}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.radioItem}>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
id="all_and_newlines"
|
||||||
|
className={styles.radioInput}
|
||||||
|
checked={stripMode === 'all_and_newlines'}
|
||||||
|
onChange={() => setStripMode('all_and_newlines')}
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
htmlFor="all_and_newlines"
|
||||||
|
className={`${styles.radioLabel} ${stripMode === 'all_and_newlines' ? styles.radioActive : ''}`}
|
||||||
|
>
|
||||||
|
{t('tools.text_space_stripper.strip_mode_all_and_newlines')}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
className={styles.button}
|
||||||
|
onClick={loadExample}
|
||||||
|
>
|
||||||
|
{t('tools.text_space_stripper.load_example')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 右侧 - 输出结果 */}
|
||||||
|
<div className="lg:col-span-6">
|
||||||
|
<div className={styles.card}>
|
||||||
|
<div className="flex items-center justify-between mb-4">
|
||||||
|
<h2 className="text-md font-medium text-primary">{t('tools.text_space_stripper.output_text')}</h2>
|
||||||
|
<button
|
||||||
|
className={styles.iconButton}
|
||||||
|
onClick={copyResult}
|
||||||
|
disabled={!outputText}
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon icon={copied ? faCheck : faCopy} className="mr-1" />
|
||||||
|
{copied ? t('tools.text_space_stripper.copied') : t('tools.text_space_stripper.copy_result')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<textarea
|
||||||
|
value={outputText}
|
||||||
|
readOnly
|
||||||
|
placeholder={t('tools.text_space_stripper.output_placeholder')}
|
||||||
|
className={styles.textarea}
|
||||||
|
rows={20}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -22,6 +22,7 @@ export const en = {
|
|||||||
jwt_decoder: tools.jwt_decoder.en,
|
jwt_decoder: tools.jwt_decoder.en,
|
||||||
qrcode_generator: tools.qrcode_generator.en,
|
qrcode_generator: tools.qrcode_generator.en,
|
||||||
text_counter: tools.text_counter.en,
|
text_counter: tools.text_counter.en,
|
||||||
|
text_space_stripper: tools.text_space_stripper.en,
|
||||||
timezone_converter: tools.timezone_converter.en,
|
timezone_converter: tools.timezone_converter.en,
|
||||||
unicode_converter: tools.unicode_converter.en,
|
unicode_converter: tools.unicode_converter.en,
|
||||||
url_encoder: tools.url_encoder.en
|
url_encoder: tools.url_encoder.en
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import jsonEditor from './json_editor';
|
|||||||
import jwtDecoder from './jwt_decoder';
|
import jwtDecoder from './jwt_decoder';
|
||||||
import qrcodeGenerator from './qrcode_generator';
|
import qrcodeGenerator from './qrcode_generator';
|
||||||
import textCounter from './text_counter';
|
import textCounter from './text_counter';
|
||||||
|
import textSpaceStripper from './text_space_stripper';
|
||||||
import timezoneConverter from './timezone_converter';
|
import timezoneConverter from './timezone_converter';
|
||||||
import unicodeConverter from './unicode_converter';
|
import unicodeConverter from './unicode_converter';
|
||||||
import urlEncoder from './url_encoder';
|
import urlEncoder from './url_encoder';
|
||||||
@@ -39,9 +40,10 @@ export const tools = {
|
|||||||
jwt_decoder: jwtDecoder,
|
jwt_decoder: jwtDecoder,
|
||||||
qrcode_generator: qrcodeGenerator,
|
qrcode_generator: qrcodeGenerator,
|
||||||
text_counter: textCounter,
|
text_counter: textCounter,
|
||||||
|
text_space_stripper: textSpaceStripper,
|
||||||
timezone_converter: timezoneConverter,
|
timezone_converter: timezoneConverter,
|
||||||
unicode_converter: unicodeConverter,
|
unicode_converter: unicodeConverter,
|
||||||
url_encoder: urlEncoder
|
url_encoder: urlEncoder
|
||||||
};
|
};
|
||||||
|
|
||||||
export default tools;
|
export default tools;
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
export const textSpaceStripperEn = {
|
||||||
|
title: 'Text Space Stripper',
|
||||||
|
description: 'Remove spaces and line breaks from text with various modes',
|
||||||
|
input_text: 'Input Text',
|
||||||
|
input_placeholder: 'Enter or paste text to process here...',
|
||||||
|
output_text: 'Output Result',
|
||||||
|
output_placeholder: 'Processed text will appear here...',
|
||||||
|
tool_options: 'Processing Options',
|
||||||
|
strip_mode: 'Strip Mode',
|
||||||
|
strip_mode_both: 'Both Sides',
|
||||||
|
strip_mode_start: 'Leading Spaces',
|
||||||
|
strip_mode_end: 'Trailing Spaces',
|
||||||
|
strip_mode_all: 'All Spaces',
|
||||||
|
strip_mode_newlines: 'All Line Breaks',
|
||||||
|
strip_mode_all_and_newlines: 'All Spaces and Line Breaks',
|
||||||
|
copy_result: 'Copy Result',
|
||||||
|
copied: 'Copied',
|
||||||
|
copy_failed: 'Copy failed',
|
||||||
|
clear: 'Clear',
|
||||||
|
process: 'Process',
|
||||||
|
load_example: 'Load Example'
|
||||||
|
};
|
||||||
|
|
||||||
|
export default textSpaceStripperEn;
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import textSpaceStripperZh from './zh';
|
||||||
|
import textSpaceStripperEn from './en';
|
||||||
|
|
||||||
|
export const textSpaceStripper = {
|
||||||
|
zh: textSpaceStripperZh,
|
||||||
|
en: textSpaceStripperEn
|
||||||
|
};
|
||||||
|
|
||||||
|
export default textSpaceStripper;
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
export const textSpaceStripperZh = {
|
||||||
|
title: '文本去空格换行',
|
||||||
|
description: '去除文本中的空格和换行符,支持多种模式',
|
||||||
|
input_text: '输入文本',
|
||||||
|
input_placeholder: '在此输入或粘贴需要处理的文本...',
|
||||||
|
output_text: '输出结果',
|
||||||
|
output_placeholder: '处理后的文本将显示在这里...',
|
||||||
|
tool_options: '处理选项',
|
||||||
|
strip_mode: '去除方式',
|
||||||
|
strip_mode_both: '两边空格',
|
||||||
|
strip_mode_start: '左边空格',
|
||||||
|
strip_mode_end: '右边空格',
|
||||||
|
strip_mode_all: '全部空格',
|
||||||
|
strip_mode_newlines: '所有换行符',
|
||||||
|
strip_mode_all_and_newlines: '所有空格和换行符',
|
||||||
|
copy_result: '复制结果',
|
||||||
|
copied: '已复制',
|
||||||
|
copy_failed: '复制失败',
|
||||||
|
clear: '清空',
|
||||||
|
process: '处理',
|
||||||
|
load_example: '加载示例'
|
||||||
|
};
|
||||||
|
|
||||||
|
export default textSpaceStripperZh;
|
||||||
@@ -22,6 +22,7 @@ export const zh = {
|
|||||||
jwt_decoder: tools.jwt_decoder.zh,
|
jwt_decoder: tools.jwt_decoder.zh,
|
||||||
qrcode_generator: tools.qrcode_generator.zh,
|
qrcode_generator: tools.qrcode_generator.zh,
|
||||||
text_counter: tools.text_counter.zh,
|
text_counter: tools.text_counter.zh,
|
||||||
|
text_space_stripper: tools.text_space_stripper.zh,
|
||||||
timezone_converter: tools.timezone_converter.zh,
|
timezone_converter: tools.timezone_converter.zh,
|
||||||
unicode_converter: tools.unicode_converter.zh,
|
unicode_converter: tools.unicode_converter.zh,
|
||||||
url_encoder: tools.url_encoder.zh
|
url_encoder: tools.url_encoder.zh
|
||||||
|
|||||||
+8
-1
@@ -1,7 +1,8 @@
|
|||||||
import {
|
import {
|
||||||
faCode, faExchangeAlt, faClock, faGlobe, faLink, faLock,
|
faCode, faExchangeAlt, faClock, faGlobe, faLink, faLock,
|
||||||
faImage, faCogs, faFileCode, faKey, faFont,
|
faImage, faCogs, faFileCode, faKey, faFont,
|
||||||
faCalendarAlt, faPalette, faEdit, faRuler, faNetworkWired
|
faCalendarAlt, faPalette, faEdit, faRuler, faNetworkWired,
|
||||||
|
faEraser
|
||||||
} from '@fortawesome/free-solid-svg-icons';
|
} from '@fortawesome/free-solid-svg-icons';
|
||||||
import { Tool } from '@/types/tools';
|
import { Tool } from '@/types/tools';
|
||||||
|
|
||||||
@@ -111,6 +112,12 @@ const tools: Tool[] = [
|
|||||||
category: ['text'],
|
category: ['text'],
|
||||||
keywords: ['字数统计', '字符统计', '字数', '词数', '行数', '计数', 'word count', 'character count', 'zishu', 'zs', 'tongji', 'tj']
|
keywords: ['字数统计', '字符统计', '字数', '词数', '行数', '计数', 'word count', 'character count', 'zishu', 'zs', 'tongji', 'tj']
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
code: 'text_space_stripper',
|
||||||
|
icon: faEraser,
|
||||||
|
category: ['text'],
|
||||||
|
keywords: ['去空格', '去换行', '去空白', '字符串处理', '文本处理', '空格删除', '换行符', 'trim', 'strip', 'space', 'whitespace', 'newline']
|
||||||
|
},
|
||||||
{
|
{
|
||||||
code: 'html_markdown_converter',
|
code: 'html_markdown_converter',
|
||||||
icon: faFileCode,
|
icon: faFileCode,
|
||||||
|
|||||||
Reference in New Issue
Block a user