How do I string.format() or sprintf() in coffeescript?
This seems to do the trick:
String.prototype.format = ->
args = arguments
return this.replace /{(\d+)}/g, (match, number) ->
return if typeof args[number] isnt 'undefined' then args[number] else match
Translated using some javascript from fearphage
Which can then be used like this:
fmt = "<p>{0} {1} (<a href='mailto:{2}'>{2}</a>)</p>"
mystring = fmt.format "Fred", "Flinstone", "[email protected]"
mystring would then be:
<p>Fred Flinstone (<a href='mailto:[email protected]'>[email protected]</a>)</p>
Using the #{var} approach (while perfect for example given) doesn't work with a string that needs to be recycled several times. In a looping situation for example:
HTML_header = fs.readFileSync('includes/notify/header.html').toString()
HTML_managerOpen = fs.readFileSync('includes/notify/managerOpen.html').toString()
HTML_student = fs.readFileSync('includes/notify/student.html').toString()
HTML_managerClose = fs.readFileSync('includes/notify/managerClose.html').toString()
HTML_footer = fs.readFileSync('includes/notify/footer.html').toString()
HTML_final = HTML_header
getter2 = (r, callback) ->
HTML_final += HTML_managerOpen.format r.EMAIL, r.FNAME, r.LNAME, r.STUDENTS.length, r.PHONE, r.MEMAIL, r.MFNAME, r.MLNAME
async.forEachSeries r.STUDENTS, getter3, (err) ->
HTML_final += HTML_managerClose
callback null
getter3 = (r, callback) ->
HTML_final += HTML_student.format r.EMAIL, r.FNAME, r.LNAME, r.PHONE, r.DESCRIPTION, r.ENROLLED, "", "", "", "", "", "", r.CERTEXAMSCORE, r.COIKEY
callback null
async.forEachSeries results, getter2, (err) ->
cback null, HTML_final + HTML_footer
So there's 2 things going on here. First is interpolation, which coffeescript directly supports using double-quoted string literals and ruby style syntax like this:
"The #{speed} #{color} #{animal} jumped over the lazy dog"
That will replace the placeholders with the corresponding variables from the local scope. That's the idiomatic way to handle string interpolation in coffeescript (and ruby).
Second is the formatting, which you should probably handle separately if you want to get numbers with specific decimal places, thousands separate with commas, leading zeros, or that sort of thing. However, CoffeeScript can interpolate the formatting as well, so you could do
"Free shipping on orders over #{currency(freeShipAmount)}"
For other features with C-style formatters, have a look at JavaScript sprintf (which I found on this answer)
This seems to do the trick:
String.prototype.format = ->
args = arguments
return this.replace /{(\d+)}/g, (match, number) ->
return if typeof args[number] isnt 'undefined' then args[number] else match
Translated using some javascript from fearphage
Which can then be used like this:
fmt = "<p>{0} {1} (<a href='mailto:{2}'>{2}</a>)</p>"
mystring = fmt.format "Fred", "Flinstone", "[email protected]"
mystring would then be:
<p>Fred Flinstone (<a href='mailto:[email protected]'>[email protected]</a>)</p>
Using the #{var} approach (while perfect for example given) doesn't work with a string that needs to be recycled several times. In a looping situation for example:
HTML_header = fs.readFileSync('includes/notify/header.html').toString()
HTML_managerOpen = fs.readFileSync('includes/notify/managerOpen.html').toString()
HTML_student = fs.readFileSync('includes/notify/student.html').toString()
HTML_managerClose = fs.readFileSync('includes/notify/managerClose.html').toString()
HTML_footer = fs.readFileSync('includes/notify/footer.html').toString()
HTML_final = HTML_header
getter2 = (r, callback) ->
HTML_final += HTML_managerOpen.format r.EMAIL, r.FNAME, r.LNAME, r.STUDENTS.length, r.PHONE, r.MEMAIL, r.MFNAME, r.MLNAME
async.forEachSeries r.STUDENTS, getter3, (err) ->
HTML_final += HTML_managerClose
callback null
getter3 = (r, callback) ->
HTML_final += HTML_student.format r.EMAIL, r.FNAME, r.LNAME, r.PHONE, r.DESCRIPTION, r.ENROLLED, "", "", "", "", "", "", r.CERTEXAMSCORE, r.COIKEY
callback null
async.forEachSeries results, getter2, (err) ->
cback null, HTML_final + HTML_footer
The idiomatic version of the accepted answer:
String::format = (args...) ->
@replace /{(\d+)}/g, (match, number) ->
if number < args.length then args[number] else match
© 2022 - 2024 — McMap. All rights reserved.