Bug Report: proper() doesn't capitalize the first letter of words preceded by punctuation.

Certified Associate Developer

My teammate found a bug when using proper() to display a label; a word preceded by a non-alphabetic character will not be converted to proper case.

If the 11th floor is home to the HR department.

  • Floor.id = 11
  • Floor.department.name = "human resources"

We would expect:

Floor 11 (Human Resources)

but instead get:

Floor 11 (human Resources)

To reproduce the issue, I used this expression to check capitalization:

proper(
  "I am reporting that ""proper() coNverts each [alphabetic] cHaRacter into ProPeR caSe " & "(unless a non-alphabetic character precedes it)"""
),

Where I would expect:

I Am Reporting That "Proper() Converts Each [Alphabetic] Character Into Proper Case (Unless A Non-alphabetic Character Precedes It)

It's returning:

I Am Reporting That "proper() Converts Each [alphabetic] Character Into Proper Case (unless A Non-alphabetic Character Precedes It)

Is proper() working as designed?

Side note: 22.4 documentation reads, "Converts each character in the text into proper case, meaning it will capitalize the first first letter of every word and convert the rest into lowercase. (https://docs.appian.com/suite/help/22.4/fnc_text_proper.html")

  Discussion posts and replies are publicly visible

  • 0
    Certified Senior Developer

    Hello ,

    Can you please show us how you are trying to achieve this?

    • Floor.id = 11
    • Floor.department.name = "human resources"

    Floor 11 (Human Resources)

  • I'm not sure this is a "bug" so much as a constraint, possibly crossed with a lack of specificity in the documention (re: the snippet you copied).  I suppose the documentation should be rephrased to something more like, "capatialize the first non-whitespace character, where applicable, of every whole word in the string".  I suppose you could argue that the function should specifically exclude non-alphabet characters from its logic, though it seems like that might be expecting too much from a function like this.

  • I agree that you will get what you get with fn!proper().  However, we can create a more robust rule that removes and replaces certain preceding characters to allow proper() to function more intuitively.  This could be optimized, quick and dirty solution to get you going:

    a!localVariables(
      local!data: "I am reporting that ""proper() coNverts each [alphabetic] cHaRacter into ProPeR caSe " & "(unless a non-alphabetic character precedes it)""",
      local!ignore: {"(",")","""","[","]","-"}, /* preceding characters you want to ignore */
      local!removals: a!flatten(
        a!forEach(
          items: 1+enumerate(len(local!data)),
          expression: a!localVariables(
            local!currentChar: charat(local!data,fv!item),
            if(
              contains(local!ignore,local!currentChar),
              {
                index: fv!item,
                char: local!currentChar
              },
              {}
            )
          )
        )
      ),
      local!replaced: if(
        rule!APN_isEmpty(local!removals),
        local!data,
        joinarray(
          a!forEach(
            items: 1+enumerate(len(local!data)),
            expression: if(
              contains(tointeger(local!removals.index),fv!item),
              " ",
              charat(local!data,fv!item)
            )
          )
        )
      ),
    
      local!proper: proper(local!replaced),
    
      joinarray(
        a!forEach(
          items: 1+enumerate(len(local!proper)),
          expression: a!localVariables(
            local!replacementIndex: wherecontains(fv!item,tointeger(local!removals.index)),
            if(
              rule!APN_isBlank(local!replacementIndex),
              charat(local!proper,fv!item),
              property(index(local!removals,local!replacementIndex,{}),"char")
            )
          )
        )
      )
    )