mirror of
https://github.com/iib0011/omni-tools.git
synced 2025-09-19 05:59:34 +02:00
Merge pull request #33 from EugSh1/main
feat: minor improvements and refactoring in Text Replacer Tool
This commit is contained in:
163
.idea/workspace.xml
generated
163
.idea/workspace.xml
generated
@@ -4,12 +4,9 @@
|
||||
<option name="autoReloadType" value="SELECTIVE" />
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="b30e2810-c4c1-4aad-b134-794e52cc1c7d" name="Changes" comment="feat: ToolContent.tsx">
|
||||
<list default="true" id="b30e2810-c4c1-4aad-b134-794e52cc1c7d" name="Changes" comment="fix: replace text service">
|
||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/components/ToolContent.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/ToolContent.tsx" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/components/examples/ToolExamples.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/examples/ToolExamples.tsx" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/image/png/change-colors-in-png/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/image/png/change-colors-in-png/index.tsx" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/list/reverse/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/list/reverse/index.tsx" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pages/tools/string/text-replacer/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/pages/tools/string/text-replacer/index.tsx" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
@@ -25,7 +22,7 @@
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_BRANCH_BY_REPOSITORY">
|
||||
<map>
|
||||
<entry key="$PROJECT_DIR$" value="main" />
|
||||
<entry key="$PROJECT_DIR$" value="fork/EugSh1/main" />
|
||||
</map>
|
||||
</option>
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||
@@ -41,6 +38,38 @@
|
||||
"assignee": "iib0011"
|
||||
}
|
||||
}</component>
|
||||
<component name="GitHubPullRequestState"><![CDATA[{
|
||||
"prStates": [
|
||||
{
|
||||
"id": {
|
||||
"id": "PR_kwDOMJIfts51PkS9",
|
||||
"number": 22
|
||||
},
|
||||
"lastSeen": 1741207144695
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"id": "PR_kwDOMJIfts6NiNYl",
|
||||
"number": 32
|
||||
},
|
||||
"lastSeen": 1741209723869
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"id": "PR_kwDOMJIfts6Nheyd",
|
||||
"number": 31
|
||||
},
|
||||
"lastSeen": 1741213371410
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"id": "PR_kwDOMJIfts6NmRBs",
|
||||
"number": 33
|
||||
},
|
||||
"lastSeen": 1741282429036
|
||||
}
|
||||
]
|
||||
}]]></component>
|
||||
<component name="GithubPullRequestsUISettings">{
|
||||
"selectedUrlAndAccountId": {
|
||||
"url": "https://github.com/iib0011/omni-tools.git",
|
||||
@@ -65,51 +94,52 @@
|
||||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent">{
|
||||
"keyToString": {
|
||||
"ASKED_ADD_EXTERNAL_FILES": "true",
|
||||
"ASKED_SHARE_PROJECT_CONFIGURATION_FILES": "true",
|
||||
"Docker.Dockerfile build.executor": "Run",
|
||||
"Docker.Dockerfile.executor": "Run",
|
||||
"Playwright.JoinText Component.executor": "Run",
|
||||
"Playwright.JoinText Component.should merge text pieces with specified join character.executor": "Run",
|
||||
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"RunOnceActivity.git.unshallow": "true",
|
||||
"Vitest.compute function (1).executor": "Run",
|
||||
"Vitest.compute function.executor": "Run",
|
||||
"Vitest.mergeText.executor": "Run",
|
||||
"Vitest.mergeText.should merge lines and preserve blank lines when deleteBlankLines is false.executor": "Run",
|
||||
"Vitest.mergeText.should merge lines, preserve blank lines and trailing spaces when both deleteBlankLines and deleteTrailingSpaces are false.executor": "Run",
|
||||
"Vitest.removeDuplicateLines function.executor": "Run",
|
||||
"Vitest.removeDuplicateLines function.newlines option.executor": "Run",
|
||||
"Vitest.removeDuplicateLines function.newlines option.should filter newlines when newlines is set to filter.executor": "Run",
|
||||
"git-widget-placeholder": "main",
|
||||
"ignore.virus.scanning.warn.message": "true",
|
||||
"kotlin-language-version-configured": "true",
|
||||
"last_opened_file_path": "C:/Users/Ibrahima/IdeaProjects/omni-tools/public/assets",
|
||||
"node.js.detected.package.eslint": "true",
|
||||
"node.js.detected.package.tslint": "true",
|
||||
"node.js.selected.package.eslint": "(autodetect)",
|
||||
"node.js.selected.package.tslint": "(autodetect)",
|
||||
"nodejs_package_manager_path": "npm",
|
||||
"npm.build.executor": "Run",
|
||||
"npm.dev.executor": "Run",
|
||||
"npm.lint.executor": "Run",
|
||||
"npm.prebuild.executor": "Run",
|
||||
"npm.script:create:tool.executor": "Run",
|
||||
"npm.test.executor": "Run",
|
||||
"npm.test:e2e.executor": "Run",
|
||||
"npm.test:e2e:run.executor": "Run",
|
||||
"prettierjs.PrettierConfiguration.Package": "C:\\Users\\Ibrahima\\IdeaProjects\\omni-tools\\node_modules\\prettier",
|
||||
"project.structure.last.edited": "Problems",
|
||||
"project.structure.proportion": "0.0",
|
||||
"project.structure.side.proportion": "0.2",
|
||||
"settings.editor.selected.configurable": "settings.typescriptcompiler",
|
||||
"ts.external.directory.path": "C:\\Users\\Ibrahima\\IdeaProjects\\omni-tools\\node_modules\\typescript\\lib",
|
||||
"vue.rearranger.settings.migration": "true"
|
||||
}
|
||||
}</component>
|
||||
<component name="PropertiesComponent"><![CDATA[{
|
||||
"keyToString": {
|
||||
"ASKED_ADD_EXTERNAL_FILES": "true",
|
||||
"ASKED_SHARE_PROJECT_CONFIGURATION_FILES": "true",
|
||||
"Docker.Dockerfile build.executor": "Run",
|
||||
"Docker.Dockerfile.executor": "Run",
|
||||
"Playwright.JoinText Component.executor": "Run",
|
||||
"Playwright.JoinText Component.should merge text pieces with specified join character.executor": "Run",
|
||||
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"RunOnceActivity.git.unshallow": "true",
|
||||
"Vitest.compute function (1).executor": "Run",
|
||||
"Vitest.compute function.executor": "Run",
|
||||
"Vitest.mergeText.executor": "Run",
|
||||
"Vitest.mergeText.should merge lines and preserve blank lines when deleteBlankLines is false.executor": "Run",
|
||||
"Vitest.mergeText.should merge lines, preserve blank lines and trailing spaces when both deleteBlankLines and deleteTrailingSpaces are false.executor": "Run",
|
||||
"Vitest.removeDuplicateLines function.executor": "Run",
|
||||
"Vitest.removeDuplicateLines function.newlines option.executor": "Run",
|
||||
"Vitest.removeDuplicateLines function.newlines option.should filter newlines when newlines is set to filter.executor": "Run",
|
||||
"Vitest.replaceText function.executor": "Run",
|
||||
"git-widget-placeholder": "#33 on fork/EugSh1/main",
|
||||
"ignore.virus.scanning.warn.message": "true",
|
||||
"kotlin-language-version-configured": "true",
|
||||
"last_opened_file_path": "C:/Users/Ibrahima/IdeaProjects/omni-tools/public/assets",
|
||||
"node.js.detected.package.eslint": "true",
|
||||
"node.js.detected.package.tslint": "true",
|
||||
"node.js.selected.package.eslint": "(autodetect)",
|
||||
"node.js.selected.package.tslint": "(autodetect)",
|
||||
"nodejs_package_manager_path": "npm",
|
||||
"npm.build.executor": "Run",
|
||||
"npm.dev.executor": "Run",
|
||||
"npm.lint.executor": "Run",
|
||||
"npm.prebuild.executor": "Run",
|
||||
"npm.script:create:tool.executor": "Run",
|
||||
"npm.test.executor": "Run",
|
||||
"npm.test:e2e.executor": "Run",
|
||||
"npm.test:e2e:run.executor": "Run",
|
||||
"prettierjs.PrettierConfiguration.Package": "C:\\Users\\Ibrahima\\IdeaProjects\\omni-tools\\node_modules\\prettier",
|
||||
"project.structure.last.edited": "Problems",
|
||||
"project.structure.proportion": "0.0",
|
||||
"project.structure.side.proportion": "0.2",
|
||||
"settings.editor.selected.configurable": "settings.typescriptcompiler",
|
||||
"ts.external.directory.path": "C:\\Users\\Ibrahima\\IdeaProjects\\omni-tools\\node_modules\\typescript\\lib",
|
||||
"vue.rearranger.settings.migration": "true"
|
||||
}
|
||||
}]]></component>
|
||||
<component name="ReactDesignerToolWindowState">
|
||||
<option name="myId2Visible">
|
||||
<map>
|
||||
@@ -178,22 +208,25 @@
|
||||
</test-names>
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="replaceText function" type="JavaScriptTestRunnerVitest" temporary="true" nameIsGenerated="true">
|
||||
<node-interpreter value="project" />
|
||||
<vitest-package value="$PROJECT_DIR$/node_modules/vitest" />
|
||||
<working-dir value="$PROJECT_DIR$" />
|
||||
<vitest-options value="--run" />
|
||||
<envs />
|
||||
<scope-kind value="SUITE" />
|
||||
<test-file value="$PROJECT_DIR$/src/pages/tools/string/text-replacer/replaceText.service.test.ts" />
|
||||
<test-names>
|
||||
<test-name value="replaceText function" />
|
||||
</test-names>
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration default="true" type="docker-deploy" factoryName="dockerfile" temporary="true">
|
||||
<deployment type="dockerfile">
|
||||
<settings />
|
||||
</deployment>
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="build" type="js.build_tools.npm" temporary="true" nameIsGenerated="true">
|
||||
<package-json value="$PROJECT_DIR$/package.json" />
|
||||
<command value="run" />
|
||||
<scripts>
|
||||
<script value="build" />
|
||||
</scripts>
|
||||
<node-interpreter value="project" />
|
||||
<envs />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="dev" type="js.build_tools.npm" temporary="true" nameIsGenerated="true">
|
||||
<package-json value="$PROJECT_DIR$/package.json" />
|
||||
<command value="run" />
|
||||
@@ -205,8 +238,8 @@
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<list>
|
||||
<item itemvalue="npm.build" />
|
||||
<item itemvalue="npm.dev" />
|
||||
<item itemvalue="Vitest.replaceText function" />
|
||||
<item itemvalue="Vitest.removeDuplicateLines function" />
|
||||
<item itemvalue="Vitest.removeDuplicateLines function.newlines option" />
|
||||
<item itemvalue="Vitest.removeDuplicateLines function.newlines option.should filter newlines when newlines is set to filter" />
|
||||
@@ -214,10 +247,10 @@
|
||||
<recent_temporary>
|
||||
<list>
|
||||
<item itemvalue="npm.dev" />
|
||||
<item itemvalue="Vitest.replaceText function" />
|
||||
<item itemvalue="Vitest.removeDuplicateLines function" />
|
||||
<item itemvalue="Vitest.removeDuplicateLines function.newlines option" />
|
||||
<item itemvalue="Vitest.removeDuplicateLines function.newlines option.should filter newlines when newlines is set to filter" />
|
||||
<item itemvalue="npm.build" />
|
||||
</list>
|
||||
</recent_temporary>
|
||||
</component>
|
||||
@@ -770,8 +803,8 @@
|
||||
<MESSAGE value="feat: remove duplicate lines" />
|
||||
<MESSAGE value="fix: tsc" />
|
||||
<MESSAGE value="style: optimizations" />
|
||||
<MESSAGE value="feat: ToolContent.tsx" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="feat: ToolContent.tsx" />
|
||||
<MESSAGE value="fix: replace text service" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="fix: replace text service" />
|
||||
</component>
|
||||
<component name="XSLT-Support.FileAssociations.UIState">
|
||||
<expand />
|
||||
|
@@ -8,12 +8,14 @@ import { tool as stringPalindrome } from './palindrome/meta';
|
||||
import { tool as stringToMorse } from './to-morse/meta';
|
||||
import { tool as stringSplit } from './split/meta';
|
||||
import { tool as stringJoin } from './join/meta';
|
||||
import { tool as stringReplace } from './text-replacer/meta';
|
||||
|
||||
export const stringTools = [
|
||||
stringSplit,
|
||||
stringJoin,
|
||||
stringRemoveDuplicateLines,
|
||||
stringToMorse
|
||||
stringToMorse,
|
||||
stringReplace
|
||||
// stringReverse,
|
||||
// stringRandomizeCase,
|
||||
// stringUppercase,
|
||||
|
147
src/pages/tools/string/text-replacer/index.tsx
Normal file
147
src/pages/tools/string/text-replacer/index.tsx
Normal file
@@ -0,0 +1,147 @@
|
||||
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.'}
|
||||
placeholder={'New text'}
|
||||
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 with replacements'} 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}
|
||||
/>
|
||||
);
|
||||
}
|
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