Substitute terms in a sentence while excluding those that are within a markdown hyperlink

I have created a function that substitutes any instances of words in an array with markdown links that lead to a glossary page.

For example:

const text = "This is an example text with an [example](example.com) markdown link.";

const highlightedWords = ["xxx", "example", "yyy"];

const replaceWords = (text: string, highlightedWords: string[]) => {
  if (highlightedWords.length == 0 || text == null) {
    return text;
  }
  return text.replace(
    new RegExp(`\\b(${highlightedWords.join("|")})\\b`, "gi"),
    `[$1](/glossary#$1)`
  );
};

console.log(replaceWords(text, highlightedWords));
// Output: This is an [example](/glossary#example) text with an [[example](/glossary#example)]([example](/glossary#example).com) markdown link.

I am facing an issue where the regex function does not ignore text fragments that are already enclosed within markdown link syntax. I would like it to do so.

Your assistance on this matter would be greatly appreciated! Thank you!

Answer №1

To start, make sure you prioritize matching the markdown links and then capture the specific words for conversion. When replacing, implement conditional logic to only convert the match if Group 1 is a match.

Check out the corrected code below:

const text = "This is an example text with an [example](example.com) markdown link.";

const highlightedWords = ["xxx", "example", "yyy"];

const replaceWords = (text, highlightedWords) => {
  if (highlightedWords.length == 0 || text == null) {
    return text;
  }
  return text.replace(
    new RegExp(String.raw`\[[^\][]*]\([^()]*\)|\b(${highlightedWords.join("|")})\b`, "gi"),
    (m, g1) => g1 ? `[${g1}](/glossary#${g1})` : m
  );
};

console.log(replaceWords(text, highlightedWords));

The \[[^\][]*]\([^()]*\) part matches

  • \[ - a [
  • [^\][]* - zero or more chars other than [ and ]
  • ]\( - a ]( string
  • [^()]* - zero or more chars other than ( and )
  • \) - a ) char

The | serves as an alternation operator.

(m, g1) => g1 ? ${g1} : m indicates that m is the match value and g1 is the matched word in the list of highlightedWords, which will be converted if not already part of a markdown link.

Answer №2

Perhaps you're looking to only convert the first match to markdown format.

Here's my proposed solution:

const content = "This is a sample text containing an [example](example.com) markdown link.";

const highlightedTerms = ["xxx", "example", "yyy"];

const replaceContent = (content, highlightedTerms) => {
  if (highlightedTerms.length === 0 || content === null) {
    return content;
  }
  return content.replace(
    new RegExp(`\\b(${highlightedTerms.join("|")})[.*\][(].*[)]\\b`, "gi"),
    `[$1](/glossary#$1)`
  );
};

console.log(replaceContent(content, highlightedTerms));

Result:

"This is a sample text containing an [example](example.com) markdown link."

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for efficiently merging various axios responses

I'm currently working on a React application where I need to create two objects using data from three different APIs. To illustrate: DataObject1 will be generated using API1 and API2. DataObject2 will be generated using API1, API2, and API3. As I c ...

Error: Import statement is invalid outside of a module in next.js

Every time I attempt to run the register.tsx page in my next.js project, I encounter the error message shown below. My Next.Js project utilizes TypeScript. import React, { useState } from 'react'; ^^^^^^ SyntaxError: Cannot use import st ...

While building with Next.js, a ReferenceError may occur if the sessionStorage is not defined

While using Next.js 13 App router, I encountered an issue with storing the JWT token received upon login in session storage. It all worked smoothly when accessing the token in my page.js pages across different routes as long as the page was a client compon ...

Error encountered during TypeScript execution - 'undefined'

I'm encountering errors while trying to instantiate a basic class named Point using HTML and TypeScript. Whenever I click on the hyperlink, I receive the following error messages within each try/catch block: Errors: Cannot read property 'Empty ...

Generate a distinct identifier for the select element ID whenever a new row of data is inserted into a table

Although my title accurately describes my issue, I believe the solutions I have been attempting may not be on the right track. I am relatively new to javascript and web development in general, so please forgive me for any lack of technical terminology. Th ...

What is the best location to insert JavaScript from a website template into a Blazor project?

I recently set up a new Blazor WebAssembly project in Visual Studio 2019 and wanted to integrate a website template. After downloading the template, I am unsure where to place the accompanying JavaScript files. Currently, I have placed them within my inde ...

What is the reason behind Angular not allowing users to define @Output events that begin with 'on'?

While developing a component, I defined an output EventEmitter named onUploaded. However, Angular flagged an error instructing me to use (uploaded) instead. This restriction is due to security concerns, as bindings starting with 'ono' pose risks. ...

Tips for seamlessly integrating XHP and ReactJS for a component's implementation

Imagine this scenario: a blog with a posts feed. Upon loading the page, three <PostCard>s are already loaded from the server-side. As the user scrolls down or clicks a Load more button, new post cards should be dynamically added to the page. We have ...

Combining Angular 2.0 within Angular 1.x: Elevating your module

Currently, I am attempting to incorporate an Angular 2.0 component within an Angular 1.x application (for experimentation and learning purposes). Upon further examination, I have observed that this can be achieved by referencing the Angular2 upgrade modul ...

There seems to be an issue with AJAX form submission and it is not functioning properly

Having trouble submitting a form to another page using ajax, as it is not sending the post request. I have included Javascript at the top of the page: <script src="http://code.jquery.com/jquery-1.9.1.js"></script> <script> $(function(){ ...

An error occurred while trying to upload the image: Undefined property 'subscribe' cannot be read

Recently, I implemented a create post function that allows users to fill in the title, content, and upload an image. However, I encountered an issue where the progress bar fills up and the image gets uploaded to Firebase successfully, but it doesn't a ...

hiding the search box by clicking away from it

Can someone help me with modifying this search box design? @import url(http://weloveiconfonts.com/api/?family=entypo); /* entypo */ [class*="entypo-"]:before { font-family: 'entypo', sans-serif; color: #C0C0C0; } * { margin: 0px; pad ...

Make the background disappear when the text field is left empty and the cursor is not present (onUnfocus)

When the text field is empty and there is no cursor in the text field, I want it to be transparent and for the spell checker not working. The result should be displayed a little to the left inside a <div>. Should this be done using CSS, JavaScript, ...

By utilizing a combination of JavaScript and jQuery, we can dynamically fill interconnected select boxes with data from an

After finding solutions to this particular query, I successfully managed to populate a select box based on the selection made in another select box. (You can see my answer here) This was achieved by retrieving data from an array structure that was generate ...

There seems to be an issue with the functionality of the JavaScript Quiz as it is

While working on my JS quiz, I encountered an issue where some answers were not displaying due to quotes and the need to escape HTML characters. Additionally, I am facing difficulty in accurately awarding points or deductions based on user responses. Curre ...

Storing a combination of input fields and radio buttons in a single state: a guide

const [isChecked, setIsChecked] = useState(false); const handleRadio = (event: { currentTarget: { value: string } }) => { const isChecked = event.currentTarget.value === 'true' ? true : false; setValues({ checked: isChecked }); }; ...

What is the method for setting a condition within the setState function?

I used if for the title: in SetConfirmDialog, but it's not working. How can I fix this? <Button color={user.active ? "success" : "error"} variant="text" startIcon={<UserCheck />} title={user.active ? &quo ...

The toLowerCase method seems to be malfunctioning along with several other functions

JS var score = 0 var yes = "yes" var pokemonName = []; var bg = []; var index = 0; document.getElementById('repete').style.visibility = 'hidden'; (function asyncLoop() { background = bg[num = Math.floor(Math.random() ...

Typescript throws an error when Redux useSelector fails to properly infer the state

Seeking guidance on how to access my state using the useSelector hook import { applyMiddleware, createStore } from 'redux'; import thunk from 'redux-thunk'; import { reducers } from './reducers'; export c ...

What is the best way to fill an array within an object using React Hooks?

I am encountering an issue with an object that includes an array. Here is the code snippet in question: const [data, setData] = useState({ jobs: [] }); Currently, I am retrieving data from an API and need to append this fetched information to the jobs arr ...