mirror of
https://github.com/iib0011/omni-tools.git
synced 2025-09-19 14:09:31 +02:00
feat: minor improvements and refactoring in Text Replacer Tool
- Changed the replaceText method to take all options as arguments. - Removed compute from SimpleRadio component. - Moved InitialValuesType type and initialValues object to a separate file to avoid Fast Refresh error. - Used ToolContent and added usage examples.
This commit is contained in:
@@ -8,12 +8,14 @@ import { tool as stringPalindrome } from './palindrome/meta';
|
|||||||
import { tool as stringToMorse } from './to-morse/meta';
|
import { tool as stringToMorse } from './to-morse/meta';
|
||||||
import { tool as stringSplit } from './split/meta';
|
import { tool as stringSplit } from './split/meta';
|
||||||
import { tool as stringJoin } from './join/meta';
|
import { tool as stringJoin } from './join/meta';
|
||||||
|
import { tool as stringReplace } from './text-replacer/meta';
|
||||||
|
|
||||||
export const stringTools = [
|
export const stringTools = [
|
||||||
stringSplit,
|
stringSplit,
|
||||||
stringJoin,
|
stringJoin,
|
||||||
stringRemoveDuplicateLines,
|
stringRemoveDuplicateLines,
|
||||||
stringToMorse
|
stringToMorse,
|
||||||
|
stringReplace
|
||||||
// stringReverse,
|
// stringReverse,
|
||||||
// stringRandomizeCase,
|
// stringRandomizeCase,
|
||||||
// stringUppercase,
|
// stringUppercase,
|
||||||
|
146
src/pages/tools/string/text-replacer/index.tsx
Normal file
146
src/pages/tools/string/text-replacer/index.tsx
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
import { Box } from '@mui/material';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import ToolTextResult from '@components/result/ToolTextResult';
|
||||||
|
import { GetGroupsType } from '@components/options/ToolOptions';
|
||||||
|
import { replaceText } from './service';
|
||||||
|
import TextFieldWithDesc from '@components/options/TextFieldWithDesc';
|
||||||
|
import ToolTextInput from '@components/input/ToolTextInput';
|
||||||
|
import SimpleRadio from '@components/options/SimpleRadio';
|
||||||
|
import { initialValues, InitialValuesType } from './initialValues';
|
||||||
|
import ToolContent from '@components/ToolContent';
|
||||||
|
import { CardExampleType } from '@components/examples/ToolExamples';
|
||||||
|
import { ToolComponentProps } from '@tools/defineTool';
|
||||||
|
|
||||||
|
const exampleCards: CardExampleType<InitialValuesType>[] = [
|
||||||
|
{
|
||||||
|
title: 'Replace specific word in text',
|
||||||
|
description:
|
||||||
|
'In this example we will replace the word "hello" with the word "hi". This example doesn\'t use regular expressions.',
|
||||||
|
sampleText: 'hello, how are you today? hello!',
|
||||||
|
sampleResult: 'hi, how are you today? hi!',
|
||||||
|
sampleOptions: {
|
||||||
|
textToReplace: 'hello, how are you today? hello!',
|
||||||
|
searchValue: 'hello',
|
||||||
|
searchRegexp: '',
|
||||||
|
replaceValue: 'hi',
|
||||||
|
mode: 'text'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Replace all numbers in text',
|
||||||
|
description:
|
||||||
|
'In this example we will replace all numbers in numbers with * using regexp. In the output we will get text with numbers replaced with *.',
|
||||||
|
sampleText: 'The price is 100$, and the discount is 20%.',
|
||||||
|
sampleResult: 'The price is X$, and the discount is X%.',
|
||||||
|
sampleOptions: {
|
||||||
|
textToReplace: 'The price is 100$, and the discount is 20%.',
|
||||||
|
searchValue: '',
|
||||||
|
searchRegexp: '/\\d+/g',
|
||||||
|
replaceValue: '*',
|
||||||
|
mode: 'regexp'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Replace all dates in text',
|
||||||
|
description:
|
||||||
|
'In this example we will replace all dates in the format YYYY-MM-DD with the word DATE using regexp. The output will have all the dates replaced with the word DATE.',
|
||||||
|
sampleText:
|
||||||
|
'The event will take place on 2025-03-10, and the deadline is 2025-03-15.',
|
||||||
|
sampleResult:
|
||||||
|
'The event will take place on DATE, and the deadline is DATE.',
|
||||||
|
sampleOptions: {
|
||||||
|
textToReplace:
|
||||||
|
'The event will take place on 2025-03-10, and the deadline is 2025-03-15.',
|
||||||
|
searchValue: '',
|
||||||
|
searchRegexp: '/\\d{4}-\\d{2}-\\d{2}/g',
|
||||||
|
replaceValue: 'DATE',
|
||||||
|
mode: 'regexp'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function Replacer({ title }: ToolComponentProps) {
|
||||||
|
const [input, setInput] = useState<string>('');
|
||||||
|
const [result, setResult] = useState<string>('');
|
||||||
|
|
||||||
|
function compute(optionsValues: InitialValuesType, input: string) {
|
||||||
|
setResult(replaceText(optionsValues, input));
|
||||||
|
}
|
||||||
|
|
||||||
|
const getGroups: GetGroupsType<InitialValuesType> = ({
|
||||||
|
values,
|
||||||
|
updateField
|
||||||
|
}) => [
|
||||||
|
{
|
||||||
|
title: 'Search text',
|
||||||
|
component: (
|
||||||
|
<Box>
|
||||||
|
<SimpleRadio
|
||||||
|
onClick={() => updateField('mode', 'text')}
|
||||||
|
checked={values.mode === 'text'}
|
||||||
|
title={'Find This Pattern in Text'}
|
||||||
|
/>
|
||||||
|
<TextFieldWithDesc
|
||||||
|
description={'Enter the text pattern that you want to replace.'}
|
||||||
|
value={values.searchValue}
|
||||||
|
onOwnChange={(val) => updateField('searchValue', val)}
|
||||||
|
type={'text'}
|
||||||
|
/>
|
||||||
|
<SimpleRadio
|
||||||
|
onClick={() => updateField('mode', 'regexp')}
|
||||||
|
checked={values.mode === 'regexp'}
|
||||||
|
title={'Find a Pattern Using a RegExp'}
|
||||||
|
/>
|
||||||
|
<TextFieldWithDesc
|
||||||
|
description={
|
||||||
|
'Enter the regular expression that you want to replace.'
|
||||||
|
}
|
||||||
|
value={values.searchRegexp}
|
||||||
|
onOwnChange={(val) => updateField('searchRegexp', val)}
|
||||||
|
type={'text'}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Replace Text',
|
||||||
|
component: (
|
||||||
|
<Box>
|
||||||
|
<TextFieldWithDesc
|
||||||
|
description={'Enter the pattern to use for replacement.'}
|
||||||
|
value={values.replaceValue}
|
||||||
|
onOwnChange={(val) => updateField('replaceValue', val)}
|
||||||
|
type={'text'}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ToolContent
|
||||||
|
title={title}
|
||||||
|
initialValues={initialValues}
|
||||||
|
getGroups={getGroups}
|
||||||
|
compute={compute}
|
||||||
|
input={input}
|
||||||
|
setInput={setInput}
|
||||||
|
inputComponent={
|
||||||
|
<ToolTextInput
|
||||||
|
title="Text to replace."
|
||||||
|
value={input}
|
||||||
|
onChange={setInput}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
resultComponent={
|
||||||
|
<ToolTextResult title={'Text to replace.'} value={result} />
|
||||||
|
}
|
||||||
|
toolInfo={{
|
||||||
|
title: 'Text Replacer',
|
||||||
|
description:
|
||||||
|
'Easily replace specific text in your content with this simple, browser-based tool. Just input your text, set the text you want to replace and the replacement value, and instantly get the updated version.'
|
||||||
|
}}
|
||||||
|
exampleCards={exampleCards}
|
||||||
|
></ToolContent>
|
||||||
|
);
|
||||||
|
}
|
15
src/pages/tools/string/text-replacer/initialValues.ts
Normal file
15
src/pages/tools/string/text-replacer/initialValues.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
export type InitialValuesType = {
|
||||||
|
textToReplace: string;
|
||||||
|
searchValue: string;
|
||||||
|
searchRegexp: string;
|
||||||
|
replaceValue: string;
|
||||||
|
mode: 'text' | 'regexp';
|
||||||
|
};
|
||||||
|
|
||||||
|
export const initialValues: InitialValuesType = {
|
||||||
|
textToReplace: '',
|
||||||
|
searchValue: '',
|
||||||
|
searchRegexp: '',
|
||||||
|
replaceValue: '',
|
||||||
|
mode: 'text'
|
||||||
|
};
|
13
src/pages/tools/string/text-replacer/meta.ts
Normal file
13
src/pages/tools/string/text-replacer/meta.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { defineTool } from '@tools/defineTool';
|
||||||
|
import { lazy } from 'react';
|
||||||
|
|
||||||
|
export const tool = defineTool('string', {
|
||||||
|
name: 'Text Replacer',
|
||||||
|
path: 'replacer',
|
||||||
|
shortDescription: 'Quickly replace text in your content',
|
||||||
|
icon: 'material-symbols-light:find-replace',
|
||||||
|
description:
|
||||||
|
'Easily replace specific text in your content with this simple, browser-based tool. Just input your text, set the text you want to replace and the replacement value, and instantly get the updated version.',
|
||||||
|
keywords: ['text', 'replace'],
|
||||||
|
component: lazy(() => import('./index'))
|
||||||
|
});
|
175
src/pages/tools/string/text-replacer/replaceText.service.test.ts
Normal file
175
src/pages/tools/string/text-replacer/replaceText.service.test.ts
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
import { replaceText } from './service';
|
||||||
|
import { initialValues } from './initialValues';
|
||||||
|
|
||||||
|
describe('replaceText function (text mode)', () => {
|
||||||
|
const mode = 'text';
|
||||||
|
|
||||||
|
it('should replace the word in the text correctly', () => {
|
||||||
|
const text = 'Lorem ipsum odor amet, consectetuer adipiscing elit.';
|
||||||
|
const searchValue = 'ipsum';
|
||||||
|
const replaceValue = 'vitae';
|
||||||
|
const result = replaceText(
|
||||||
|
{ ...initialValues, searchValue, replaceValue, mode },
|
||||||
|
text
|
||||||
|
);
|
||||||
|
expect(result).toBe('Lorem vitae odor amet, consectetuer adipiscing elit.');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should replace letters in the text correctly', () => {
|
||||||
|
const text =
|
||||||
|
'Luctus penatibus montes elementum lacus mus vivamus lacus laoreet.';
|
||||||
|
const searchValue = 'e';
|
||||||
|
const replaceValue = 'u';
|
||||||
|
const result = replaceText(
|
||||||
|
{ ...initialValues, searchValue, replaceValue, mode },
|
||||||
|
text
|
||||||
|
);
|
||||||
|
expect(result).toBe(
|
||||||
|
'Luctus punatibus montus ulumuntum lacus mus vivamus lacus laoruut.'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the original text if one of the required arguments is an empty string', () => {
|
||||||
|
const text =
|
||||||
|
'Nostra netus quisque ornare neque dolor sem nostra venenatis.';
|
||||||
|
expect(
|
||||||
|
replaceText(
|
||||||
|
{ ...initialValues, searchValue: '', replaceValue: 'test', mode },
|
||||||
|
text
|
||||||
|
)
|
||||||
|
).toBe('Nostra netus quisque ornare neque dolor sem nostra venenatis.');
|
||||||
|
expect(
|
||||||
|
replaceText(
|
||||||
|
{ ...initialValues, searchValue: 'ornare', replaceValue: 'test', mode },
|
||||||
|
''
|
||||||
|
)
|
||||||
|
).toBe('');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should replace multiple occurrences of the word correctly', () => {
|
||||||
|
const text = 'apple orange apple banana apple';
|
||||||
|
const searchValue = 'apple';
|
||||||
|
const replaceValue = 'grape';
|
||||||
|
const result = replaceText(
|
||||||
|
{ ...initialValues, searchValue, replaceValue, mode },
|
||||||
|
text
|
||||||
|
);
|
||||||
|
expect(result).toBe('grape orange grape banana grape');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the original text if the replace value is an empty string', () => {
|
||||||
|
const text = 'apple orange apple banana apple';
|
||||||
|
const searchValue = 'apple';
|
||||||
|
const replaceValue = '';
|
||||||
|
const result = replaceText(
|
||||||
|
{ ...initialValues, searchValue, replaceValue, mode },
|
||||||
|
text
|
||||||
|
);
|
||||||
|
expect(result).toBe(' orange banana ');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the original text if the search value is not found', () => {
|
||||||
|
const text = 'apple orange banana';
|
||||||
|
const searchValue = 'grape';
|
||||||
|
const replaceValue = 'melon';
|
||||||
|
const result = replaceText(
|
||||||
|
{ ...initialValues, searchValue, replaceValue, mode },
|
||||||
|
text
|
||||||
|
);
|
||||||
|
expect(result).toBe('apple orange banana');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('replaceText function (regexp mode)', () => {
|
||||||
|
const mode = 'regexp';
|
||||||
|
|
||||||
|
it('should replace a word in text using regexp correctly', () => {
|
||||||
|
const text = 'Egestas lobortis facilisi convallis rhoncus nunc.';
|
||||||
|
const searchRegexp = '/nunc/';
|
||||||
|
const replaceValue = 'hello';
|
||||||
|
const result = replaceText(
|
||||||
|
{ ...initialValues, searchRegexp, replaceValue, mode },
|
||||||
|
text
|
||||||
|
);
|
||||||
|
expect(result).toBe('Egestas lobortis facilisi convallis rhoncus hello.');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should replace all words in the text with regexp correctly', () => {
|
||||||
|
const text =
|
||||||
|
'Parturient porta ultricies tellus ultricies suscipit quisque torquent.';
|
||||||
|
const searchRegexp = '/ultricies/g';
|
||||||
|
const replaceValue = 'hello';
|
||||||
|
const result = replaceText(
|
||||||
|
{ ...initialValues, searchRegexp, replaceValue, mode },
|
||||||
|
text
|
||||||
|
);
|
||||||
|
expect(result).toBe(
|
||||||
|
'Parturient porta hello tellus hello suscipit quisque torquent.'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should replace words in text with regexp using alternation operator correctly', () => {
|
||||||
|
const text =
|
||||||
|
'Commodo maximus nullam dis placerat fermentum curabitur semper.';
|
||||||
|
const searchRegexp = '/nullam|fermentum/g';
|
||||||
|
const replaceValue = 'test';
|
||||||
|
const result = replaceText(
|
||||||
|
{ ...initialValues, searchRegexp, replaceValue, mode },
|
||||||
|
text
|
||||||
|
);
|
||||||
|
expect(result).toBe(
|
||||||
|
'Commodo maximus test dis placerat test curabitur semper.'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the original text when passed an invalid regexp', () => {
|
||||||
|
const text =
|
||||||
|
'Commodo maximus nullam dis placerat fermentum curabitur semper.';
|
||||||
|
const searchRegexp = '/(/';
|
||||||
|
const replaceValue = 'test';
|
||||||
|
const result = replaceText(
|
||||||
|
{ ...initialValues, searchRegexp, replaceValue, mode },
|
||||||
|
text
|
||||||
|
);
|
||||||
|
expect(result).toBe(
|
||||||
|
'Commodo maximus nullam dis placerat fermentum curabitur semper.'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should remove brackets from text correctly using regexp', () => {
|
||||||
|
const text =
|
||||||
|
'Porta nulla (magna) lectus, [taciti] habitant nunc urna maximus metus.';
|
||||||
|
const searchRegexp = '/[()\\[\\]]/g';
|
||||||
|
const replaceValue = '';
|
||||||
|
const result = replaceText(
|
||||||
|
{ ...initialValues, searchRegexp, replaceValue, mode },
|
||||||
|
text
|
||||||
|
);
|
||||||
|
expect(result).toBe(
|
||||||
|
'Porta nulla magna lectus, taciti habitant nunc urna maximus metus.'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should replace case-insensitive words correctly', () => {
|
||||||
|
const text = 'Porta cras ad laoreet porttitor feRmeNtum consectetur?';
|
||||||
|
const searchRegexp = '/porta|fermentum/gi';
|
||||||
|
const replaceValue = 'test';
|
||||||
|
const result = replaceText(
|
||||||
|
{ ...initialValues, searchRegexp, replaceValue, mode },
|
||||||
|
text
|
||||||
|
);
|
||||||
|
expect(result).toBe('test cras ad laoreet porttitor test consectetur?');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should replace words with digits and symbols correctly', () => {
|
||||||
|
const text = 'The price is 100$, and the discount is 20%.';
|
||||||
|
const searchRegexp = '/\\d+/g';
|
||||||
|
const replaceValue = 'X';
|
||||||
|
const result = replaceText(
|
||||||
|
{ ...initialValues, searchRegexp, replaceValue, mode },
|
||||||
|
text
|
||||||
|
);
|
||||||
|
expect(result).toBe('The price is X$, and the discount is X%.');
|
||||||
|
});
|
||||||
|
});
|
40
src/pages/tools/string/text-replacer/service.ts
Normal file
40
src/pages/tools/string/text-replacer/service.ts
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import { InitialValuesType } from './initialValues';
|
||||||
|
|
||||||
|
function isFieldsEmpty(textField: string, searchField: string) {
|
||||||
|
return !textField.trim() || !searchField.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function replaceText(options: InitialValuesType, text: string) {
|
||||||
|
const { searchValue, searchRegexp, replaceValue, mode } = options;
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case 'text':
|
||||||
|
if (isFieldsEmpty(text, searchValue)) return text;
|
||||||
|
return text.replaceAll(searchValue, replaceValue);
|
||||||
|
case 'regexp':
|
||||||
|
if (isFieldsEmpty(text, searchRegexp)) return text;
|
||||||
|
return replaceTextWithRegexp(text, searchRegexp, replaceValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function replaceTextWithRegexp(
|
||||||
|
text: string,
|
||||||
|
searchRegexp: string,
|
||||||
|
replaceValue: string
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const match = searchRegexp.match(/^\/(.*)\/([a-z]*)$/i);
|
||||||
|
|
||||||
|
if (match) {
|
||||||
|
// Input is in /pattern/flags format
|
||||||
|
const [, pattern, flags] = match;
|
||||||
|
return text.replace(new RegExp(pattern, flags), replaceValue);
|
||||||
|
} else {
|
||||||
|
// Input is a raw pattern - don't escape it
|
||||||
|
return text.replace(new RegExp(searchRegexp, 'g'), replaceValue);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Invalid regular expression:', err);
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user