Skip to content

Instantly share code, notes, and snippets.

@davidchambers
Created June 1, 2012 17:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save davidchambers/2853692 to your computer and use it in GitHub Desktop.
Save davidchambers/2853692 to your computer and use it in GitHub Desktop.
String extensions
escapeRegExpChars = (string) ->
# Copied from https://github.com/slevithan/XRegExp.
string.replace /[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'
deconstructRegExp = (regexp) ->
/// ^/(.+)[/]([gimy]*)$ ///.exec regexp
# Create a pattern like the one provided, but with a start of string
# anchor:
#
# > anchorStart(/https?:\/\//)
# /^https?:\/\//
#
# If a string pattern is provided, any "special" characters are
# escaped:
#
# > anchorStart("?")
# /^\?/
#
anchorStart = (pattern) ->
if typeof pattern is 'string'
RegExp "^#{escapeRegExpChars pattern}"
else
match = deconstructRegExp pattern
RegExp "^#{match[1]}", match[2]
# Create a pattern like the one provided, but with an end of string
# anchor:
#
# > anchorEnd(/[.](ac[.]nz|edu)/)
# /[.](ac[.]nz|edu)$/
#
# If a string pattern is provided, any "special" characters are
# escaped:
#
# > anchorEnd(".edu")
# /\.edu$/
#
anchorEnd = (pattern) ->
if typeof pattern is 'string'
RegExp "#{escapeRegExpChars pattern}$"
else
match = deconstructRegExp pattern
RegExp "#{match[1]}$", match[2]
# Create a sorted copy of an array of patterns. The sort order is
# dictated by String::lstrip and String::rstrip, which:
#
# * try regexp patterns before string patterns
# * try regexp patterns in argument order
# * try string patterns in descending length order
#
# Examples:
#
# > sorter(["http", "https"])
# ["https", "http"]
#
# > sorter([/xxx/, /y/, /zz/])
# [/xxx/, /y/, /zz/]
#
# > sorter([/\d/, "::", /tr(ol){3,}/, ".", "..."])
# [/\d/, /tr(ol){3,}/, "...", "::", "."]
#
sorter = (patterns) ->
regexps = []
strings = []
for pattern in patterns
(if _.isRegExp pattern then regexps else strings).push pattern
regexps.concat _.sortBy strings, (s) -> -s.length
# String::lstrip
# --------------
#
# Strip characters from the beginning of the string if they match the
# pattern provided:
#
# > "?key=value".lstrip("?")
# "key=value"
#
# The pattern may be a regular expression:
#
# > "https://github.com".lstrip(/https?:\/\//)
# "github.com"
#
# If multiple patterns are provided, the longest matching substring
# is stripped:
#
# > "https://github.com".lstrip("http", "https").lstrip("://")
# "github.com"
#
# The above could be rewritten as:
#
# > "https://github.com".lstrip("http://", "https://")
# "github.com"
#
String::lstrip = (patterns...) ->
for pattern in sorter patterns
match = anchorStart(pattern).exec this
return @substr match[0].length if match
@toString()
# String::rstrip
# --------------
#
# Strip characters from the end of the string if they match the
# pattern provided:
#
# > "/jespern/".rstrip("/")
# "/jespern"
#
# The pattern may be a regular expression:
#
# > "<B>foo</B> bar <B>baz</B>".rstrip(/<\/b>/i)
# "<B>foo</B> bar <B>baz"
#
# If multiple patterns are provided, the longest matching substring
# is stripped:
#
# > "pseudo ellipsis...".rstrip(".", "...")
# "pseudo ellipsis"
#
String::rstrip = (patterns...) ->
for pattern in sorter patterns
match = anchorEnd(pattern).exec this
return @substr 0, @length - match[0].length if match
@toString()
# String::startsWith
# ------------------
#
# Determine whether the provided pattern matches the beginning of the
# string:
#
# > "https://github.com".startsWith("http://")
# false
# > "https://github.com".startsWith("https://")
# true
#
# The pattern may be a regular expression:
#
# > "https://github.com".startsWith(/https?:\/\//)
# true
#
# If multiple patterns are provided, the question is whether at least
# one matches the beginning of the string:
#
# > "https://github.com".startsWith("http://", "https://")
# true
#
String::startsWith = (patterns...) ->
for pattern in patterns
return yes if anchorStart(pattern).test this
no
# String::endsWith
# ----------------
#
# Determine whether the provided pattern matches the end of the
# string:
#
# > "http://www.com.edu".endsWith(".com")
# false
# > "http://www.com.edu".endsWith(".edu")
# true
#
# The pattern may be a regular expression:
#
# > "jsmith@com.edu".endsWith(/[.](ac[.]nz|edu)/)
# true
#
# If multiple patterns are provided, the question is whether at least
# one matches the end of the string:
#
# > "jsmith@com.edu".endsWith(".ac.nz", ".edu")
# true
#
String::endsWith = (patterns...) ->
for pattern in patterns
return yes if anchorEnd(pattern).test this
no
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment