Sfoglia il codice sorgente

Merge pull request #381 from ghalliday/bug85660

BUG: #85660 Add a Str.ToTitleCase to match unicode

Reviewed-By: Richard Chapman <rchapman@hpccsystems.com>
Richard Chapman 13 anni fa
parent
commit
95db26c7bb

+ 11 - 1
ecllibrary/std/Str.ecl

@@ -146,7 +146,7 @@ EXPORT STRING ToUpperCase(STRING src) := lib_stringlib.StringLib.StringToUpperCa
 /**
  * Returns the argument string with the first letter of each word in upper case and all other
  * letters left as-is.
- * A contiguous sequence of alphabetic characters is treated as a word.
+ * A contiguous sequence of alphanumeric characters is treated as a word.
  * 
  * @param src           The string that is being converted.
  */
@@ -154,6 +154,16 @@ EXPORT STRING ToUpperCase(STRING src) := lib_stringlib.StringLib.StringToUpperCa
 EXPORT STRING ToCapitalCase(STRING src) := lib_stringlib.StringLib.StringToCapitalCase(src);
 
 /**
+ * Returns the argument string with the first letter of each word in upper case and all other
+ * letters lower case.
+ * A contiguous sequence of alphanumeric characters is treated as a word.
+ *
+ * @param src           The string that is being converted.
+ */
+
+EXPORT STRING ToTitleCase(STRING src) := lib_stringlib.StringLib.StringToTitleCase(src);
+
+/**
  * Returns the argument string with all characters in reverse order.
  * Note the argument is not TRIMMED before it is reversed.
  * 

+ 27 - 0
ecllibrary/teststd/str/TestToTitleCase.ecl

@@ -0,0 +1,27 @@
+/*##############################################################################
+## Copyright (c) 2011 HPCC Systems.  All rights reserved.
+############################################################################## */
+
+IMPORT Std.Str;
+
+EXPORT TestToTitleCase := MODULE
+
+  EXPORT TestConstant := MODULE
+    EXPORT Test01 := ASSERT(Str.ToTitleCase('@ABCXYZ['+x'60'+'abcdxyz{ '+x'99')+'X' = '@Abcxyz['+x'60'+'Abcdxyz{ '+x'99'+'X', CONST);
+    EXPORT Test02 := ASSERT(Str.ToTitleCase('')+'X' = 'X', CONST);
+    EXPORT Test03 := ASSERT(Str.ToTitleCase(' John Doe ')+'X' = ' John Doe X', CONST);
+    EXPORT Test04 := ASSERT(Str.ToTitleCase(' john doe ')+'X' = ' John Doe X', CONST);
+    EXPORT Test05 := ASSERT(Str.ToTitleCase(' john,doe ')+'X' = ' John,Doe X', CONST);
+    EXPORT Test06 := ASSERT(Str.ToTitleCase(' JOHN,DOE ')+'X' = ' John,Doe X', CONST);
+    EXPORT Test07 := ASSERT(Str.ToTitleCase(' john-doe ')+'X' = ' John-Doe X', CONST);
+    EXPORT Test08 := ASSERT(Str.ToTitleCase(' john\tdoe ')+'X' = ' John\tDoe X', CONST);
+    EXPORT Test09 := ASSERT(Str.ToTitleCase('john doe')+'X' = 'John DoeX', CONST);
+    EXPORT Test10 := ASSERT(Str.ToTitleCase('a b c d')+'X' = 'A B C DX', CONST);
+    EXPORT Test11 := ASSERT(Str.ToTitleCase('john macdonald')+'X' = 'John MacdonaldX', CONST);
+    EXPORT Test12 := ASSERT(Str.ToTitleCase('99john 5doe')+'X' = '99john 5doeX', CONST);          // could argue j,d should be Titleized
+    //This needs to be properly defined.  Should upper/Title work on accented characters if possible
+    //EXPORT Test13 := ASSERT(Str.ToTitleCase('jähn mäcdonald')+'X' = 'Jähn MäcdonaldX', CONST);
+    //EXPORT Test14 := ASSERT(Str.ToTitleCase('ähn mäcdonald')+'X' = 'Ähn MäcdonaldX', CONST);
+  END;
+
+END;

+ 1 - 0
install_directory/ecllibrary.install

@@ -68,6 +68,7 @@ Install (
     ${CMAKE_CURRENT_SOURCE_DIR}/ecllibrary/teststd/str/TestSubstituteIncluded.ecl
     ${CMAKE_CURRENT_SOURCE_DIR}/ecllibrary/teststd/str/TestToLowerCase.ecl
     ${CMAKE_CURRENT_SOURCE_DIR}/ecllibrary/teststd/str/TestToCapitalCase.ecl
+    ${CMAKE_CURRENT_SOURCE_DIR}/ecllibrary/teststd/str/TestToTitleCase.ecl
     ${CMAKE_CURRENT_SOURCE_DIR}/ecllibrary/teststd/str/TestToUpperCase.ecl
     ${CMAKE_CURRENT_SOURCE_DIR}/ecllibrary/teststd/str/TestWildMatch.ecl
     ${CMAKE_CURRENT_SOURCE_DIR}/ecllibrary/teststd/str/TestWordCount.ecl

+ 21 - 1
plugins/stringlib/stringlib.cpp

@@ -31,9 +31,10 @@ static const char * compatibleVersions[] = {
     "STRINGLIB 1.1.09",
     "STRINGLIB 1.1.10",
     "STRINGLIB 1.1.11",
+    "STRINGLIB 1.1.12",
     NULL };
 
-#define STRINGLIB_VERSION "STRINGLIB 1.1.12"
+#define STRINGLIB_VERSION "STRINGLIB 1.1.13"
 
 const char * EclDefinition =  
 "export StringLib := SERVICE\n"
@@ -56,6 +57,7 @@ const char * EclDefinition =
 "  string StringToUpperCase(const string src) : c,pure,entrypoint='slStringToUpperCase';\n"
 "  string StringToProperCase(const string src) : c,pure,entrypoint='slStringToProperCase';\n"
 "  string StringToCapitalCase(const string src) : c,pure,entrypoint='slStringToCapitalCase';\n"
+"  string StringToTitleCase(const string src) : c,pure,entrypoint='slStringToTitleCase';\n"
 "  integer4 StringCompareIgnoreCase(const string src1, string src2) : c,pure,entrypoint='slStringCompareIgnoreCase';\n"
 "  string StringReverse(const string src) : c,pure,entrypoint='slStringReverse';\n"
 "  string StringFindReplace(const string src, const string stok, const string rtok) : c,pure,entrypoint='slStringFindReplace';\n"
@@ -921,6 +923,24 @@ STRINGLIB_API void STRINGLIB_CALL slStringToCapitalCase(unsigned & tgtLen, char
 
 // -----------------------------------------------------------------
 
+STRINGLIB_API void STRINGLIB_CALL slStringToTitleCase(unsigned & tgtLen, char * & tgt, unsigned srcLen, const char * src)
+{
+    char * const result = (char *)CTXMALLOC(parentCtx, srcLen);
+
+    bool upperPending = true;
+    for (unsigned int i=0;i<srcLen;i++)
+    {
+        byte c = src[i];
+        result[i] = upperPending ? toupper(c) : tolower(c);
+        upperPending = !isalnum(c);
+    }
+
+    tgt = result;
+    tgtLen = srcLen;
+}
+
+// -----------------------------------------------------------------
+
 STRINGLIB_API int STRINGLIB_CALL slStringCompareIgnoreCase (unsigned src1Len, const char * src1, unsigned src2Len, const char * src2)
 {
     unsigned int i;

+ 1 - 0
plugins/stringlib/stringlib.hpp

@@ -57,6 +57,7 @@ STRINGLIB_API void STRINGLIB_CALL slStringToLowerCase(unsigned & tgtLen, char *
 STRINGLIB_API void STRINGLIB_CALL slStringToUpperCase(unsigned & tgtLen, char * & tgt, unsigned srcLen, const char * src);
 STRINGLIB_API void STRINGLIB_CALL slStringToProperCase(unsigned & tgtLen, char * & tgt, unsigned srcLen, const char * src);
 STRINGLIB_API void STRINGLIB_CALL slStringToCapitalCase(unsigned & tgtLen, char * & tgt, unsigned srcLen, const char * src);
+STRINGLIB_API void STRINGLIB_CALL slStringToTitleCase(unsigned & tgtLen, char * & tgt, unsigned srcLen, const char * src);
 STRINGLIB_API void STRINGLIB_CALL slStringToLowerCase80(char * tgt, unsigned srcLen, const char * src);
 STRINGLIB_API void STRINGLIB_CALL slStringToUpperCase80(char * tgt, unsigned srcLen, const char * src);
 STRINGLIB_API int STRINGLIB_CALL slStringCompareIgnoreCase (unsigned src1Len, const char * src1, unsigned src2Len, const char * src2);