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,
|
||||
qrcode_generator: tools.qrcode_generator.en,
|
||||
text_counter: tools.text_counter.en,
|
||||
text_space_stripper: tools.text_space_stripper.en,
|
||||
timezone_converter: tools.timezone_converter.en,
|
||||
unicode_converter: tools.unicode_converter.en,
|
||||
url_encoder: tools.url_encoder.en
|
||||
|
||||
@@ -16,6 +16,7 @@ import jsonEditor from './json_editor';
|
||||
import jwtDecoder from './jwt_decoder';
|
||||
import qrcodeGenerator from './qrcode_generator';
|
||||
import textCounter from './text_counter';
|
||||
import textSpaceStripper from './text_space_stripper';
|
||||
import timezoneConverter from './timezone_converter';
|
||||
import unicodeConverter from './unicode_converter';
|
||||
import urlEncoder from './url_encoder';
|
||||
@@ -39,9 +40,10 @@ export const tools = {
|
||||
jwt_decoder: jwtDecoder,
|
||||
qrcode_generator: qrcodeGenerator,
|
||||
text_counter: textCounter,
|
||||
text_space_stripper: textSpaceStripper,
|
||||
timezone_converter: timezoneConverter,
|
||||
unicode_converter: unicodeConverter,
|
||||
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,
|
||||
qrcode_generator: tools.qrcode_generator.zh,
|
||||
text_counter: tools.text_counter.zh,
|
||||
text_space_stripper: tools.text_space_stripper.zh,
|
||||
timezone_converter: tools.timezone_converter.zh,
|
||||
unicode_converter: tools.unicode_converter.zh,
|
||||
url_encoder: tools.url_encoder.zh
|
||||
|
||||
+8
-1
@@ -1,7 +1,8 @@
|
||||
import {
|
||||
faCode, faExchangeAlt, faClock, faGlobe, faLink, faLock,
|
||||
faImage, faCogs, faFileCode, faKey, faFont,
|
||||
faCalendarAlt, faPalette, faEdit, faRuler, faNetworkWired
|
||||
faCalendarAlt, faPalette, faEdit, faRuler, faNetworkWired,
|
||||
faEraser
|
||||
} from '@fortawesome/free-solid-svg-icons';
|
||||
import { Tool } from '@/types/tools';
|
||||
|
||||
@@ -111,6 +112,12 @@ const tools: Tool[] = [
|
||||
category: ['text'],
|
||||
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',
|
||||
icon: faFileCode,
|
||||
|
||||
Reference in New Issue
Block a user