0

quick question, I have some markdown HTML content that I'd like to convert from double asterisks to bold.

the error i'm getting is: `Uncaught TypeError: Cannot call method 'replace' of null '

here's the jsfiddle: http://jsfiddle.net/fz5ZT/9/

here's the HTML:

<div class="comments">comment 1** is good**</div>
<div class="comments">comment 2**is bad**</div>

here's the JS:

function markdown(markdownable){

  var boldMatch = markdownable.match(/\*\*[A-Za-z0-9]+\*\*/gim), 
  boldReplace = boldMatch.replace(/\*\*[A-z0-9]+\*\*/gim, '<span style="font-  weight:bold;color:blue;">'+boldMatch+'</span>'),                   
  markdownable = markdownable.replace(boldMatch, boldReplace),    
  markdownable = markdownable.replace(/\*\*/gi, "");

  return markdownable;
}

$('.comments').each(function(){  
   var markdownable=$(this).html(), comments=markdown(markdownable);
});

if you might be able to help i'd greatly appreciate it,

thanks, tim

update thanks all! please see this for a working demo: http://jsfiddle.net/fz5ZT/30/

tim peterson
  • 23,653
  • 59
  • 177
  • 299
  • If the bold rexep doesn't match, "boldMatch" will be null. "null" has no (prototype) property "replace" to call - throwing the error. – Bergi Apr 19 '12 at 17:18
  • thanks Bergi, but why is "boldMatch" null if I'm feeding it the variable `mardownable` which contains text with double asterisks? Shouldn't it match? – tim peterson Apr 19 '12 at 17:48
  • No, there is a whitespace in markdownable which is matched by neither of your regexps. – Bergi Apr 19 '12 at 17:55

5 Answers5

7
markdownable = markdownable.replace( /\*\*(.+?)\*\*/gm, '<strong>$1</strong>' );

However, instead of performing a half-hearted, well-intentioned, doomed-to-fail attempt at reinventing the wheel, why not just use an existing JavaScript Markdown library?

Edit: Here's a more robust regex that (like Markdown) requires there to be no whitespace right after the "open" or before the "close":

var bold = /\*\*(\S(.*?\S)?)\*\*/gm;
markdownable = markdownable.replace( bold, '<strong>$1</strong>' );
Phrogz
  • 296,393
  • 112
  • 651
  • 745
  • See https://developer.mozilla.org/en/JavaScript/Guide/Regular_Expressions#Using_Parentheses — it refers to the text that was found and captured inside the **1st** set of parentheses (as counted from the left by where the left parenthesis was seen). – Phrogz Apr 19 '12 at 17:59
  • thanks, great, I had seen that before but didn't know what it meant! – tim peterson Apr 19 '12 at 18:04
  • hi Phrogz, i realized this helps with the regex part but still doesn't answer why the `replace` method is null. There are 2 comments containing asterisks shouldn't the replace method have 2 strings to replace? – tim peterson Apr 19 '12 at 18:30
  • I don't know what you mean by "why the replace method is null". There are lots of other good comments and answers telling you why your previous code was broken. Read them for more insight on your old code. My single line above replaces all that nonsense, all four lines of your function. – Phrogz Apr 19 '12 at 18:39
  • hi all, please see this jsfiddle for a working demo: http://jsfiddle.net/fz5ZT/30/ – tim peterson Apr 19 '12 at 18:48
2

Your first regex match is ignoring the whitespace in the string. you need to add a space to your allowed character set, [ a-z0-9]; you don't need the the A-Z because of the i.

Also, match returns an array, so you need to get the first match, boldMatch[0] in order to access the string returned.

Evan Davis
  • 35,493
  • 6
  • 50
  • 57
1

You don't want to call .replace() on boldMatch until you know that there is a value in there to work with, that is, if there was no match.

Safer computing:

var boldMatch = markdownable.match(/\*\*[A-Za-z0-9]+\*\*/gim);
if (boldMatch) { 
  var boldReplace = boldMatch.replace(/\*\*[A-z0-9]+\*\*/gim, '<span style="font- weight:bold;color:blue;">'+boldMatch+'</span>');
}

etc.

Update:

This line of code also makes it difficult to trace what's going on:

var markdownable=$(this).html(), comments=markdown(markdownable);

Declaring two variables on one line with var is generally frowned on. Better:

var markdownable=$(this).html();
if (markdownable) {
    comments=markdown(markdownable);
}
David Gorsline
  • 4,933
  • 12
  • 31
  • 36
1

May be you can take a look at the following solution :

Find text string using jQuery?

I believe you need to do do something very similar :

  $('*:contains("I am a simple string")').each(function(){
 if($(this).children().length < 1) 
      $(this).html( 
           $(this).text().replace(
                /"I am a simple string"/
                ,'<span containsStringImLookingFor="true">"I am a simple string"   </span>' 
           )  
       ) 
});

For making the element bold you need to use the addClass() once the replace has taken place.

Thanks

Community
  • 1
  • 1
Anirban
  • 589
  • 3
  • 16
  • 40
1
function markdown(markdownable) {

    var boldMatch = markdownable.match(/[\*]{2}( .+)?[\*]{2}/gim);
    if (boldMatch && (boldMatch = boldMatch[0])) {
        var boldReplace = boldMatch.replace(/[\*]{2}( .+)+?[\*]{2}/gim, '<span style="font-weight:bold;color:blue;">' + boldMatch + '</span>');
        markdownable = markdownable.replace(boldMatch, boldReplace);
        markdownable = markdownable.replace(/\*\*/gi, "");
    }
    return markdownable;
}

$('.comments').each(function() {

    var markdownable = $(this).html(),
        comments = markdown(markdownable);

    console.log(comments);
});​

this is by far not the best solution... however it is the 'fix' for your attempt. Hopefully you can learn something about where you went wrong.

rlemon
  • 17,518
  • 14
  • 92
  • 123
  • Note that there's no reason to use `[\*]` instead of just `\*` in the regex. And why are you requiring a space at the start of the contents? – Phrogz Apr 19 '12 at 17:27
  • because it appears that was the requirement for the match. `**bad` `** good` – rlemon Apr 19 '12 at 17:32
  • Oh; I personally doubt that's what was meant, since that's not in the original regex, and the opposite of what Markdown requires. I thought "good" and "bad" were just indications of comments. But perhaps you're correct. – Phrogz Apr 19 '12 at 17:36
  • as for the `[]` i generally put them in place for readability... but yes you are right that is a personal thing. – rlemon Apr 19 '12 at 17:41
  • hi Phrogz and rlemon, thanks for your answers/comments, the space in front of `good` but not `bad` was purely accidental. I was just trying to have multiple divs with text that should be made bold. Regarding the, `[\*]` vs. `\*` , i'm not that familiar with regex, can you explain the difference? Is it just readibility? Also, rlemon, you say this is "by far not the best solution", can you point me to a better approach? – tim peterson Apr 19 '12 at 17:55
  • @timpeterson in that case the space in the regex is not required. if you are trying to match SO markdown then the space is actually a bad thing and should negate the bold. – rlemon Apr 19 '12 at 17:56
  • yes, i'm trying to match SO markdown, what is the space you are referring to? Is it the space in this code in your answer: `( .+)`? vs. `(.+)` – tim peterson Apr 19 '12 at 17:59
  • 1
    yes.. and as you will ** see** **this** only works on specific cases. – rlemon Apr 19 '12 at 18:00
  • cool now I get it, let me ** try** <--that had a space in front, this does --> **not** – tim peterson Apr 19 '12 at 18:01
  • rlemon, sorry to bug you, but i plugged your solution into the jsfiddle and it still doesn't replace the text. can you have a look as to why the markdown() function isn't working? http://jsfiddle.net/fz5ZT/18/ – tim peterson Apr 19 '12 at 18:26
  • because you need to tell it to. you're setting the variable but not doing anything with it :P silly tim. http://jsfiddle.net/rlemon/fz5ZT/21/ – rlemon Apr 19 '12 at 18:31