refactor code, deside use class or only function: class Highliter {
  constructor(where_search, any_patterns) {
    this.where_search = where_search;
    this.any_patterns = any_patterns; // expected as an object { regex: className }
  }

  search_for_replace() {
    // mimic json encode/decode safely by cloning string (redundant in JS but keeping structure)
    let where_search = JSON.parse(JSON.stringify(this.where_search));

    // replace new lines with spaces
    where_search = where_search.replace(/\n/g, ' ');

    console.log(JSON.stringify(["any_patterns", this.any_patterns]));
    console.log(JSON.stringify(["where_search", where_search]));

    const ready_all_patterns = [];
    const ready_for_replace_style = [];

    for (const [patternStr, className] of Object.entries(this.any_patterns)) {
      // Create RegExp object from string pattern 
      //(assume patternStr includes delimiters and 
      //flags like "/pattern/gi")
      // Remove slashes and parse flags manually:
      const match = patternStr.match(/^\/(.+)\/([gimsuy]*)$/);
      if (!match) continue; // skip invalid patterns
      const [_, patternBody, flags] = match;

      const regex = new RegExp(patternBody, flags);

      // Find all matches
      let matchArray;
      while ((matchArray = regex.exec(where_search)) !== null) {
        const for_replace = matchArray[0];
        const what_search_for_replace = for_replace;
        const replace_style = `<span class='${className}'>${for_replace}</span>`;

        if (!ready_all_patterns.includes(what_search_for_replace)) {
          ready_all_patterns.push(what_search_for_replace);
          ready_for_replace_style.push(replace_style);
        }

        // Avoid infinite loop if zero width match:
        if (regex.lastIndex === match.index) {
          regex.lastIndex++;
        }
      }
    }

    const res = {
      ready_all_patterns,
      ready_for_replace_style,
      where_search,
    };

    // console.log("search_for_replace(), ", JSON.stringify(res));
    return res;
  }

  string_replace_run() {
    const data = this.search_for_replace();
    let res = data.where_search;
  
    data.ready_all_patterns.forEach((pattern, index) => {
      const replacement = data.ready_for_replace_style[index];
      
      while (res.includes(pattern)) {
		//Without the loop, only one occurrence would be replaced.
        res = res.replace(pattern, replacement);
      }
    });

  return res;
  }

  regex_replace_run() {
    const data = this.search_for_replace();

    let res = data.where_search;
    data.ready_all_patterns.forEach((pattern, index) => {
      // Using word boundaries like in PHP: /\bpattern\b/
      const escapedPattern = pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
      const regex = new RegExp(`\\b${escapedPattern}\\b`, 'g');
      res = res.replace(regex, data.ready_for_replace_style[index]);
    });

    // console.log(JSON.stringify(["Result from regex_replace_run:", res]));
    return res;
  }

  regex_replace_run_lookbehind() {
    const data = this.search_for_replace();
    const new_style = [];

    // Adjust styles if they contain $ character
    for (let style of data.ready_for_replace_style) {
      if (style.includes('$')) {
        style = style.replace(/\$/g, '\\$').replace('</span>', '') + '</span>';
      }
      new_style.push(style);
    }
    data.ready_for_replace_style = new_style;


      let res = data.where_search;
      data.ready_all_patterns.forEach((pattern, index) => {
        let safePattern = pattern;
        let regex;

        if (pattern.includes('$')) {
          safePattern = safePattern.replace(/\$/g, '\\$').replace(/\./g, '\\.');
          // pattern for negative lookbehind (note: JS supports fixed length lookbehind in latest versions)
          // Adjust lookbehind pattern if needed (adjust string as per your original logic)
          const lookbehind = '(?<!par\\s{1,3}value\\s{1,3})'; 
          regex = new RegExp(lookbehind + safePattern, 'g');
        } else {
          // if you want to fallback to matching as is if no '$'
          regex = new RegExp(safePattern, 'g');
        }
        result = res.replace(regex, data.ready_for_replace_style[index]);
      });
    return res;
  }
}