How to traverse string and replace ** with b / b

8

Lately I have used some systems that have the following function, when writing a text between ** it turns this text in bold for example:

July * henrique * dos Santos

Expected result will be:

Julio henrique dos Santos

I thought about creating something similar using javascript and html, but I encountered many difficulties:

Div result:

<div id="text"></div>

JavaScript and jQuery code:

var str = "Visit jsduflsd fjkdsufdsjlkfds djfuldsifjdlsk *jflusdlkfjdsds* jfdisufkljds!";
var res = str.replace("*", "<b>");
$("#text").html(res);

Unfortunately I could not get out of there. It exchanges the first * with a <b> , but it does not close it, and it has to be something flexible to do whenever that occurs in the string . Is there any way? I thought about REGEX, but I do not know if it would be appropriate.

    
asked by anonymous 01.11.2018 / 21:14

2 answers

10

Using regex:

var str = "*Visit* jsduflsd \*fjkdsufdsjlkfds\* djfuldsifjdlsk *jflusdlkfjdsds* jfdisufkljds!";
var res = (" "+str).replace(/([^\])\*([^\*]*)([^\])\*/g, "$1<b>$2$3</b>");
res = res.trim();
res = res.replace(/\\*/g, "*");
document.write(res)
  • ( Starts character capture
  • [^\] Any character that is different from \
  • ) Closes character capture
  • \* Starts with * to \ to escape
  • ( Starts character capture
  • % with% all characters other than [^\*]* repeated 0 or many times
  • * Closes character capture
  • ) Starts character capture
  • ( Any character that is different from [^\]
  • \ Closes character capture
  • ) Ends with \* a * to escape
  • \ , $1 and $2 Used to "paste" what was captured

To get all $3 not preceded by * is to be able to escape them, however this requires a character before \ , if the string starts with bold markdown, it will fail because it will not there is a previous character. To solve this, a * is added before ( ) and it is then extracted with (" "+str) . It is also necessary to "reset" this previous character, so the trim and $1 After making the change to the HTML tags then the markdowns escaped ( $2 to \* )

Most Dynamic Usage Example:

String.prototype.markdown = function(caracter, tag) {
  return (" "+this).replace(new RegExp('([^\\])\${caracter.split('').join('\')}([^\${caracter.split('').join('\')}]*)([^\\])\${caracter.split('').join('\')}', 'g'), '$1<${tag}>$2$3</${tag}>').trim().split('\${caracter}').join(caracter);
}

document.querySelector('textarea').oninput = function() {
  document.querySelector('p').innerHTML = this.value.markdown('*', 'b').markdown('--', 'strike');
}
<textarea cols='75'>--riscado-- \--riscado\-- *negrito* \*negrito\*</textarea>

<p>

From a space in * to load with the example

    
01.11.2018 / 21:20
3

Regex is certainly the most practical and straightforward way to solve the problem as @GuilheremCostamilam has already shown. The replace getting a string as a replacement works only for one substitution and not all, so you would not have to solve it without regex.

The MDN reinforces this point clearly

  

If pattern is a string, only the first occurrence will be replaced

However it would also be possible to resolve manually, albeit much more laborious. For this, it would have to have a boolean variable to know if it will add the beginning of the tag or end of the tag, and every time it finds a * it makes the change by the start / closing according to boolean. After each change you have to toggle the Boolean.

Example:

var str = "Visit *jsduflsd* fjkdsufdsjlkfds djfuldsifjdlsk *jflusdlkfjdsds* jfdisufkljds!";

let inicio = true, res = "";
for (let letra of str){
  if (letra === '*'){
    res += inicio ? "<b>": "</b>";
    inicio = !inicio;
  }
  else res += letra;
}

document.write(res);

If there is a possibility that there is a * lost without its pair and we do not want it to be bold, then some additional concerns are already needed, which will complicate and increase the code a bit.

Example:

var str = "Visit *jsduflsd* fjkdsufdsjlkfds djfuldsifjdlsk *jflusdlkfjdsds jfdisufkljds!";

let emBold = false, res = "", blocoBold ="";
for (let letra of str){
  if (letra === '*'){
    emBold = !emBold;
    if (emBold)
      blocoBold = "";
    else //só no fecho é que adiciona o bloco todo
      res += "<b>" + blocoBold + "</b>";
  }
  else {
    if (emBold)
      blocoBold += letra;
    else 
      res += letra;
  }
}

res += blocoBold;//adiciona o que ficou por fechar sem as tags
document.write(res);
    
02.11.2018 / 00:27