 # codecs.register_error that is able to handle UnicodeEncodeErrors.
 # String::encode = ->
 
-# S.expandtabs([tabsize]) -> string
-# 
+# S.expandtabs([tabsize])-> string
+#
 # Return a copy of S where all tab characters are expanded using spaces.
 # If tabsize is not given, a tab size of 8 characters is assumed.
 # String::expandtabs = ->
 
-# S.format(*args, **kwargs) -> unicode
+# S.format(*args, **kwargs)-> unicode
 # String::format = ->
 
-# S.index(sub [,start [,end]]) -> int
-# 
+# S.index(sub [,start [,end]])-> int
+#
 # Like S.find() but raise ValueError when the substring is not found.
 # String::index = ->
 
-# S.ljust(width[, fillchar]) -> string
-# 
-# Return S left-justified in a string of length width. Padding is
-# done using the specified fill character (default is a space).
-# String::ljust = ->
-
-# S.partition(sep) -> (head, sep, tail)
-# 
+# S.partition(sep)-> (head, sep, tail)
+#
 # Search for the separator sep in S, and return the part before it,
 # the separator itself, and the part after it.  If the separator is not
 # found, return S and two empty strings.
 # String::partition = ->
 
-# S.replace (old, new[, count]) -> string
-# 
+# S.replace (old, new[, count])-> string
+#
 # Return a copy of string S with all occurrences of substring
 # old replaced by new.  If the optional argument count is
 # given, only the first count occurrences are replaced.
 # String::replace = ->
 
-# S.rfind(sub [,start [,end]]) -> int
-# 
+# S.rfind(sub [,start [,end]])-> int
+#
 # Return the highest index in S where substring sub is found,
 # such that sub is contained within s[start:end].  Optional
 # arguments start and end are interpreted as in slice notation.
-# 
+#
 # Return -1 on failure.
 # String::rfind = ->
 
-# S.rindex(sub [,start [,end]]) -> int
-# 
+# S.rindex(sub [,start [,end]])-> int
+#
 # Like S.rfind() but raise ValueError when the substring is not found.
 # String::rindex = ->
 
-# S.rjust(width[, fillchar]) -> string
-# 
-# Return S right-justified in a string of length width. Padding is
-# done using the specified fill character (default is a space)
-# String::rjust = ->
-
-# S.rpartition(sep) -> (tail, sep, head)
-# 
+# S.rpartition(sep)-> (tail, sep, head)
+#
 # Search for the separator sep in S, starting at the end of S, and return
 # the part before it, the separator itself, and the part after it.  If the
 # separator is not found, return two empty strings and S.
 # String::rpartition = ->
 
-# S.rsplit([sep [,maxsplit]]) -> list of strings
-# 
+# S.rsplit([sep [,maxsplit]])-> list of strings
+#
 # Return a list of the words in the string S, using sep as the
 # delimiter string, starting at the end of the string and working
 # to the front.  If maxsplit is given, at most maxsplit splits are

# able to handle UnicodeDecodeErrors.
# String::decode = ->

# S.encode([encoding[,errors]]) -> object
# 
# Encodes S using the codec registered for encoding. encoding defaults
# to the default encoding. errors may be given to set a different error
# handling scheme. Default is 'strict' meaning that encoding errors raise

String::title = -> (word.capitalize() for word in @split(' ')).join(' ')

# Test if the string is title and there is at least one cased character.
String::istitle = -> return true if "#{@}" is @title() and isCaseable(@); return false

# Return a copy of the string with leading whitespace removed,
# if characters are passed in thoes characters will be removed instead.
String::lstrip = (s)-> ss = '\\s\\s*'; ss = "(#{s})+" if s?; @replace(new RegExp("^#{ss}"), '')

# Return a copy of the string with trailing whitespace removed,
# if characters are passed in thoes characters will be removed instead.
String::rstrip = (s)-> ss = '\\s*\\s'; ss = "(#{s})+" if s?; @replace(new RegExp("#{ss}$"), '')
    #TODO: implement this without regex:
    #`re = new RegExp(ss); i = @length; continue while re.test(@charAt(--i)); @[0...i+1]`

# Return a copy of the string with leading and trailing whitespace removed,
# if characters are passed in thoes characters will be removed instead.
# Uses the native `trim` if it's available and only whitespace is being stripped.
String::strip = (s)-> return @trim() if not s and @trim; @lstrip(s).rstrip(s)

# Return the number of non-overlapping occurrences of a string in the string.
# Optional arguments start and end are interpreted as in slice notation.
String::count = (c, s, e)-> @slice(s, e).match(new RegExp(c, 'g'))?.length or 0

# Return the lowest index in the string where a string is found.
# Optional arguments start and end are interpreted as in slice notation.
# Return -1 if no match if found.
String::find = (c, s, e)-> i = @slice(s, e).indexOf(c); return -1 if i is -1; i+(s or 0)

# Test if all characters in the string are alphanumeric.
# Use `A-Za-z` instead of `A-z` becuase `A-z` matches `-` for some reason...
String::isalnum = -> @match(/[A-Za-z0-9]+/)?[0] is "#{@}"

# Test if all characters in the string are alphabetic.
String::isalpha = -> @match(/[A-Za-z]+/)?[0] is "#{@}"

# Test if all characters in the string are digits.
String::isdigit = -> @match(/\d+/)?[0] is "#{@}"

# Test if all characters in the string are whitespace.
String::isspace = -> @match(/\s+/)?[0] is "#{@}"

# Return a string which is the concatenation of the strings in an array.
# The separator between elements is the string.
String::join = (a)-> a.join(@)

# Return S left-justified in a string of length width. Padding is
# done using the specified fill character (default is a space).
String::ljust = (w, c=' ')-> [c,t]=["#{c}","#{@}"]; return t unless w and c; t="#{t}#{c}" while(t.length < w); t

# Return S right-justified in a string of length width. Padding is
# done using the specified fill character (default is a space)
String::rjust = (w, c=' ')-> [c,t]=["#{c}","#{@}"]; return t unless w and c; t="#{c}#{t}" while(t.length < w); t

# Pad a numeric string S with zeros on the left, to fill a field
# of the specified width.  The string S is never truncated.
String::zfill = (w)-> "#{@}".rjust(w, 0)

# Test if the string contains any of the passed in strings.
# Python strings do not have a 'contains' function, but javascript doesn't have a way of saying `'foo' in 'foobar'`.
# With this method the python `in` check would be written like this: `'foobar'.contains('foo')`
String::contains = (s...)-> (return true if @indexOf(i) isnt -1) for i in s; return false

# C style string formatting
# `'%d %s and %d %s'.cformat(2, 'cats', 6, 'dogs')` --> '2 cats and 6 dogs'
# `'%.2f liters'.cformat(2.2483545345)` --> '2.25 liters'
# `'%02d:%02d.%02d'.cformat(9, 36, 28)` --> 09:36.28
String::cformat = (args...)->
    return '' unless @
    pad = (v,l,c)-> "#{v}".zfill(l, c)
    @replace(/%(s|\.?[0-9]*f|0?[0-9]*d)/g, (match, type)->
        arg = args.shift()
        if fmatch = type.match(/(\.?)([0-9]*)f/)
            arg = parseFloat(arg)
            if fmatch[1] is '.' and fmatch[2]
                return "#{arg.toFixed(fmatch[2])}"
            else
                return "#{arg}"
        if imatch = type.match(/(0?)([0-9]*)d/)
            arg = parseInt(arg, 10)
            if imatch.length > 1 and imatch[2]
                return "#{arg}".rjust(imatch[2], imatch[1] or ' ')
            else
                return "#{arg}"
        return "#{arg}"
    )

# Return an integer hash of the string
String::hash = ()->
    hash = 0
    for i in [0...@length]
        hash= (hash<<5)-hash+@charCodeAt(i)
        hash= hash & hash # Convert to 32bit integer
    return hash

# TODO: implement these

# S.center(width[, fillchar])-> string
#
# Return S centered in a string of length width. Padding is
# done using the specified fill character (default is a space)
# String::center = ->

# S.decode([encoding[,errors]])-> object
#
# Decodes S using the codec registered for encoding. encoding defaults
# to the default encoding. errors may be given to set a different error
# handling scheme. Default is 'strict' meaning that encoding errors raise
