<commit_before>import { Pipe, Inject, PipeTransform } from '@angular/core';

@Pipe({
  name: 'tags'
})

/**
 * Tags pipe
 */
export class TagsPipe implements PipeTransform {

  /**
   * Tags
   */
  tags = {
    url: {
      rule: /(\b(https?|ftp|file):\/\/[^\s\]]+)/gim,
      template: '<a href="$1" target="_blank" rel="noopener noreferrer">$1</a>'
    },
    mail: {
      rule: /([a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)/gim,
      template: '<a href="mailto:$1" target="_blank" rel="noopener noreferrer">$1</a>'
    },
    hash: {
      rule: /(^|\s||)#(\w+)/gim,
      template: '$1<a href="/newsfeed/tag/$2;ref=hashtag">#$2</a>'
    },
    at: {
      rule: /(^|\s|\W)@(\w*[a-zA-Z_-]+\w*)/gim,
      template: '$1<a class="tag" href="/$2" target="_blank">@$2</a>'
    }
  };

  /**
   * Replace tags
   * @param str
   * @param tagName
   */
  replaceTokens(str, tagName) {
    let tag = this.tags[tagName];
    return str.replace(tag.rule, tag.template);
  }

  transform(value: string): string {
    value = this.replaceTokens(value, 'url');
    value = this.replaceTokens(value, 'mail',);
    value = this.replaceTokens(value, 'hash');
    value = this.replaceTokens(value, 'at');
    return value;
  }
}
<commit_msg>bug: build string output char by char<commit_after>import { Pipe, Inject, PipeTransform } from '@angular/core';

@Pipe({
  name: 'tags'
})

/**
 * Tags pipe
 */
export class TagsPipe implements PipeTransform  {

  results = [];

  /**
   * Tags
   */
  tags = {
    url: {
      rule: /(\b(https?|ftp|file):\/\/[^\s\]]+)/gim,
      replace: (m) => {
        return `<a href="${m.match[1]}" target="_blank" rel="noopener noreferrer">${m.match[1]}</a>`;
      }
    },
    mail: {
      rule: /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/gim,
      replace: (m) => {
        return `<a href="mailto:${m.match[0]}" target="_blank" rel="noopener noreferrer">${m.match[0]}</a>`;
      }
    },
    hash: {
      rule: /#\w+/gim,
      // rule: /(^|\s||)#(\w+)/gim,
      replace: (m) => {
        return  `<a href="/newsfeed/tag/${m.match[0].substring(1)};ref=hashtag" target="_blank">${m.match[0]}</a>`;
      }
    },
    at: {
      rule: /(^|\s|\W)@(\w*[a-zA-Z_-]+\w*)/gim,
      replace: (m) => {
        return `${m.match[1]}<a class="tag" href="/${m.match[2]}" target="_blank">@${m.match[2]}</a>`;
      }
    }
  };

  /**
   * Push a match to results array
   * @param match
   */
  push(match: any) {
    // ignore match inside others
    if (this.results.findIndex(m => match.start >= m.start && match.end <= m.end) !== -1) {
      return;
    }
    this.results.push(match);
  }

  /**
   * Parse tags
   * @param tag
   * @param value
   */
  parse(tag: string, value: string) {
    let match;
    while ((match = this.tags[tag].rule.exec(value)) !== null) {
      this.push({
        type: tag,
        start: match.index,
        end: match.index + match[0].length,
        match: match
      });
    }
  }

  /**
   * Replace tags
   * @param str
   */
  replace(str) {
    this.results.forEach(m => {
      str = str.replace(m.match[0], this.tags[m.type].replace(m, str));
    });

    return str;
  }

  transform(value: string): string {
    this.results = [];
    this.parse('url', value);
    this.parse('mail', value);
    this.parse('hash', value);
    this.parse('at', value);

    this.results.sort((a,b) => a.start-b.start );
    let html = [];
    let copyStartIndex = 0;
    for (let i=0; i<this.results.length; i++)
    {
      let tag = this.results[i];
      html.push(value.substring(copyStartIndex, tag.start));
      copyStartIndex = tag.end;

      html.push(this.tags[tag.type].replace(tag));

      if (i == this.results.length - 1){
        html.push(value.substring(copyStartIndex));
      }
    }
    console.log(html);
    return html.join('');

    //return this.replace(value);

  }

}

{'fraction_non_alphanumeric': 0.25520317145688803, 'fraction_numerical': 0.014370664023785926, 'mean_word_length': 2.456335616438356, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '333750', 'n_tokens_mistral': 1682, 'n_tokens_neox': 1644, 'n_words': 252}