views:

281

answers:

1

I'm writing a function to "title case" strings e.g. "this is a title" to "This is a Title." The following line doesn't work because the regex group reference is lost (or so I assume). Is there an easy way to uppercase my matching letter in the replace function?

replace( $input, '\b[a-z]' , upper-case('$0'))
+1  A: 

the \b expression is not part of XML Schema regular expressions. It is treated as just the character b, and so you are matching b followed by another character.

Your replacement string here upper-case('$0') is just $0 and so you are replacing the character(s) with themselves.

You can't do this using the replace function - you need something more like xsl:analyze-string from XSLT, but this is not available in XQuery 1.0.

As far as I can tell the only way to solve this is with a recursive function. A simpler solution using tokenize could be used if you do not need to preserve your seperators.

declare function local:title-case($arg as xs:string) as xs:string
{
  if (string-length($arg) = 0)
  then
    ""
  else
    let $first-word := tokenize($arg, "\s")[1]
    let $first := substring($arg, 1, 1)
    return 
      if (string-length($first-word) = 0)
      then
        concat($first, local:title-case(substring($arg, 2)))
      else
        if ($first-word = "a" (: or any other word that should not be capitalized :))
        then
          concat($first-word,
                 local:title-case(substring($arg, string-length($first-word) + 1)))
        else
          concat(upper-case($first),
                 substring($first-word, 2),
                 local:title-case(substring($arg, string-length($first-word) + 1)))
};

You will also need to ensure that the first word of every title is capitalized even when it is a short word like "a", but I leave that as an exercise to the reader.

Oliver Hallam