Search code examples
javascriptregexangulartypescriptangular-pipe

Replace link using regex


Flow:

An array of strings comes from the server, for example, ["com"] or ["c", "o", "m"].

It is necessary:

Highlight characters in links if there are matches with data that came from the server, that is, an array of strings.

Angular pipe

export class HighlightLettersPipe implements PipeTransform {
    transform(text: any, regexGroups?: string[]): any {
        if (text && regexGroups.length) {
            regexGroups.forEach(element => {
                let pattern = element.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
                pattern = pattern.split(' ').filter((t) => {
                    return t.length > 0;
                }).join('|');

                let reg = new RegExp(pattern, 'gi');
                text = text.replace(reg, match => {
                    return `<span class="replace-part">${match}</span>`;
                });
            });
            return text;
        } else {
            return text;
        }
    }
}

Everything works fine when an array with one element arrives, for example ["com"].

enter image description here

Problem

When an array with several elements arrived - ["c", "o", "m"], the symbols are highlighted, but also the markup is inserted.

enter image description here

This is because the method replace is used, which returns a new line each time.

After making the first pass and making the highlighting of the characters, a new line is returned with an added span tag. Then a new pass is made and the symbols are already highlighted in the tag span, but it is necessary that only the symbols of the original link are always highlighted.

In the end something comes out:

enter image description here

Maybe someone has encountered a similar problem and will help solve it. Thank you.


Solution

  • You could use this trick: instead of replacing directly to <span> tags, add some placeholders like ~~~~~ for opening tag and ----- for closing one, and replace that with actual tags afterwards. This way it will not collide

    regexGroups.forEach(element => {
        // ...
        let reg = new RegExp(pattern, 'gi');
        text = text.replace(reg, match => {
            return `~~~~~${match}-----`;
        });
    });
    
    // this part must be outside your forEach() block
    text = text.replace(/~~~~~/g, '<span class="replace-part">');
    text = text.replace(/-----/g, '</span>');