Development/String Classes

From The Document Foundation Wiki
Jump to: navigation, search

Throughout the codebase are two different families of string classes in use. Each of them has different features but efforts are ongoing to limit the use to one string family, with OUString for UTF-16 strings, and OString for 8bit strings. For better or worse, OString/OUString is modelled after the immutable Java String class, except with a contradictory additional operator+=

Favored Family, C++

Favored Family, C

Favored Family, C++ Helpers

Favored Family, C Helpers

Deprecated

  • String include/tools/string.hxx, deprecated 16bit string (other typedefs for this type: UniString XubString in include/tools/solar.h), implementation at tools/source/string/tustring.cxx (removed completely as of 2014-02-03)
  • ByteString has already been removed completely, mentioned for completeness only; corresponds to OString/OStringBuffer
  • xub_StrLen integer type associated with String/ByteString, which have a maximum size of 64k (i.e. unsigned short, #define xub_StrLen sal_uInt16 in include/tools/solar.h) (removed completely as of 2014-02-03)
  • STRING_MAXLEN/STRING_LEN/STRING_NOTFOUND maximum length of String: 64k, often used as invalid value/sentinel

Namespacing of OUString/OString

The rtl::OUString and rtl::OString classes are in the rtl namespace, but since they are already in practice namespaced by the O- prefix, for ease of reading it is not necessary to explicitly refer to the rtl namespace when using them in code that is not part of public API (i.e. most of the codebase).

Conversion Macros between OUString and OString

  • OString aOString = OUStringToOString( aOUString, RTL_TEXTENCODING_UTF8 );
  • OUString aOUString = OStringToOUString( aOString, RTL_TEXTENCODING_UTF8 );

Accessing the char* Data Buffer

Use SAL_DEBUG or SAL_INFO for debug output.

If you want to dump these strings with gdb, see Development/How to debug#Dumping Strings (etc)

Iterating through an OUString

Since sal_Unicode is a 16 bits type, using a simple for loop with aString[n] might cause problem UTF-16 codepoints coded on two words. If you need to iterate on an OUString that might contain such codepoints, use rtl::rtl_uString_iterateCodePoints or aString.iterateCodePoints(&index).

Iterating through a String

There are many loops over the UTF-16 code units in a String, and usually the loops use index variables of type xub_Strlen (typedef for unsigned short). Since the OUString has a higher capacity these loops must be converted so that the index variable is sal_Int32. It may be even better to use OUString.iterateCodePoints, which iterates over Unicode code points; see previous section.

Favored Methods Utilizing String Literals

Both rtl::OString and rtl::OUString have specialized overloads for string literals that treat them efficiently, and string literals are automatically converted to rtl::OString/rtl::OUString when needed, or rtl::OString/rtl::OUString functions have overloads to handle them:

if (string == "foo")

functionTakingOUString( "bar" ); // and just "" instead of OUString() for empty string

if( string.endsWith( "foo" )) ...

Please note that this auto-conversion does not work in the following cases, and you still need an explicit OUString constructor:

  • bFoo ? "bar" : "baz" [ you need bFoo ? OUString("bar") : OUString("baz"), and so on ]
  • return "foo"
  • aAny << "foo"
  • CPPUNIT_ASSERT_EQUAL("foo")

The RTL_CONSTASCII_STRINGPARAM and RTL_CONSTASCII_USTRINGPARAM macros are obsolete, and so are the various *AsciiL functions.

Empty string can be simply written as "" instead of OUString().

Cross reference for OString/OUString vs. String/UniString

In favor of OString/OUString to obsolete String/UniString, we can easily replace the later by the former as far as the following corresponding functions involve:

OUString UniString(String) note
OUString intern() const UniString intern() const;
static OUString createFromAscii( const sal_Char * value ) SAL_THROW(()) static UniString CreateFromAscii( const sal_Char* pAsciiStr ); It may be sufficient to omit completely, see string literals section above.

static UniString CreateFromAscii( const sal_Char* pAsciiStr, xub_StrLen nLen ); It may be sufficient to omit completely, see string literals section above.
static OUString number( int i, sal_Int16 radix = 10 ) static UniString CreateFromInt32( sal_Int32 n, sal_Int16 nRadix = 10 );
static OUString number( long long ll, sal_Int16 radix = 10 ) static UniString CreateFromInt64( sal_Int64 n, sal_Int16 nRadix = 10 );
static OUString number( float f ) static UniString CreateFromFloat( float f );
static OUString number( double d ) static UniString CreateFromDouble( double d );

static const UniString& EmptyString();
sal_Int32 toInt32( sal_Int16 radix = 10 ) const SAL_THROW(()) sal_Int32 ToInt32() const;
sal_Int64 toInt64( sal_Int16 radix = 10 ) const SAL_THROW(()) sal_Int64 ToInt64() const;
float toFloat() const SAL_THROW(()) float ToFloat() const;
double toDouble() const SAL_THROW(()) double ToDouble() const;

UniString& Assign( const UniString& rStr );
OUString & operator=( const OUString & str ) SAL_THROW(()) UniString& Assign( const rtl::OUString& rStr );

UniString& Assign( const sal_Unicode* pCharStr );

UniString& Assign( const sal_Unicode* pCharStr, xub_StrLen nLen );

UniString& Assign( sal_Unicode c );

inline UniString & Assign(char c) // ...but allow "Assign('a')"

UniString& AssignAscii( const sal_Char* pAsciiStr );

UniString& AssignAscii( const sal_Char* pAsciiStr, xub_StrLen nLen );
OUString & operator=( const OUString & str ) SAL_THROW(()) UniString& operator =( const UniString& rStr )

UniString& operator =( const rtl::OUString& rStr )

UniString& operator =( const sal_Unicode* pCharStr )

UniString& operator =( sal_Unicode c )

inline UniString & operator =(char c) // ...but allow "= 'a'"
OUString & operator+=( const OUString & str ) SAL_THROW(()) UniString& Append( const UniString& rStr );

UniString& Append( const sal_Unicode* pCharStr );

UniString& Append( const sal_Unicode* pCharStr, xub_StrLen nLen );

UniString& Append( sal_Unicode c );

inline UniString & Append(char c) // ...but allow "Append('a')"

UniString& AppendAscii( const sal_Char* pAsciiStr );

UniString& AppendAscii( const sal_Char* pAsciiStr, xub_StrLen nLen );

UniString& operator +=( const sal_Unicode* pCharStr )

UniString& operator +=( sal_Unicode c )

inline UniString & operator +=(char c) // ...but allow "+= 'a'"

void SetChar( xub_StrLen nIndex, sal_Unicode c ); Use OUStringBuffer.setCharAt(sal_Int32 index, sal_Unicode ch)

sal_Unicode GetChar( xub_StrLen nIndex ) const // Use operator[]
sal_Int32 getLength() const SAL_THROW(()) xub_StrLen Len() const Sometimes it is sufficient (and better) to use isEmpty().
OUString replaceAt( sal_Int32 index, sal_Int32 count, const OUString& newStr ) const SAL_THROW(()) UniString& Insert( const UniString& rStr, xub_StrLen nIndex = STRING_LEN ); Pass count=0 to not replace but only insert characters. Instead of the default nIndex=STRING_LEN argument an explicit getLength() of the string to be modified must be passed as index parameter.
The OUString function does not modify the object but returns a modified copy.

UniString& Insert( const UniString& rStr, xub_StrLen nPos, xub_StrLen nLen, xub_StrLen nIndex = STRING_LEN );

UniString& Insert( const sal_Unicode* pCharStr, xub_StrLen nIndex = STRING_LEN );

UniString& InsertAscii( const sal_Char* pAsciiStr, xub_StrLen nIndex = STRING_LEN );
OUString replaceAt( sal_Int32 index, sal_Int32 count, const OUString& newStr ) const SAL_THROW(()) UniString& Replace( xub_StrLen nIndex, xub_StrLen nLen, const UniString& rStr ); The OUString function does not modify the object but returns a modified copy.

UniString& ReplaceAscii( xub_StrLen nIndex, xub_StrLen nLen, const sal_Char* pAsciiStr, xub_StrLen nStrLen = STRING_LEN );
OUString replaceAt( sal_Int32 index, sal_Int32 count, const OUString& newStr ) const SAL_THROW(()) UniString& Erase( xub_StrLen nIndex = 0, xub_StrLen nCount = STRING_LEN ); //if nIndex is set then can use replaceAt with an arg of an empty string. If Erase is called with all default args to blank the entire string, just assign a new empty OUString as a replacement. The single argument Erase(nPos) erases from nPos to the end of the string.
OUString copy( sal_Int32 beginIndex, sal_Int32 count ) const SAL_THROW(()) UniString Copy( xub_StrLen nIndex = 0, xub_StrLen nCount = STRING_LEN ) const; //if nCount is not set then use the copy() overload without count that will copy until the end of the String

UniString& Fill( xub_StrLen nCount, sal_Unicode cFillChar = ' ' );

UniString& Expand( xub_StrLen nCount, sal_Unicode cExpandChar = ' ' );

UniString& EraseLeadingChars( sal_Unicode c = ' ' );

UniString& EraseTrailingChars( sal_Unicode c = ' ' );
OUString trim() const SAL_THROW(()) UniString& EraseLeadingAndTrailingChars( sal_Unicode c = ' ' ); //trim(); is similar to default UniString equivalent, but different in that all char less than or equal to space are removed, substitute with care

UniString& EraseAllChars( sal_Unicode c = ' ' );

UniString& Reverse();

UniString& ConvertLineEnd( LineEnd eLineEnd );

UniString& ConvertLineEnd()
OUString toAsciiLowerCase() const SAL_THROW(()) UniString& ToLowerAscii(); The OUString function does not modify the object but returns a modified copy.
OUString toAsciiUpperCase() const SAL_THROW(()) UniString& ToUpperAscii(); The OUString function does not modify the object but returns a modified copy.
sal_Int32 compareTo( const OUString & str, sal_Int32 maxLength ) const SAL_THROW(()) StringCompare CompareTo( const UniString& rStr, xub_StrLen nLen = STRING_LEN ) const; Please be careful with CompareTo(). For s1.compareTo(s2) it is sufficient to use operator==. But s1.compareTo(s2, length-of-s2) would be s1.startsWith(s2).

StringCompare CompareTo( const sal_Unicode* pCharStr, xub_StrLen nLen = STRING_LEN ) const;

StringCompare CompareToAscii( const sal_Char* pAsciiStr, xub_StrLen nLen = STRING_LEN ) const; Please be careful, because "compareToAscii(RTL_CONSTASCII_STRINGPARAM(s)) != compareTo(s)"
sal_Int32 compareToIgnoreAsciiCase( const OUString & str ) const SAL_THROW(());

sal_Int32 compareToIgnoreAsciiCaseAscii( const sal_Char * asciiStr ) const SAL_THROW(());

StringCompare CompareIgnoreCaseToAscii( const UniString& rStr, xub_StrLen nLen = STRING_LEN ) const;

StringCompare CompareIgnoreCaseToAscii( const sal_Unicode* pCharStr, xub_StrLen nLen = STRING_LEN ) const;
StringCompare CompareIgnoreCaseToAscii( const sal_Char* pAsciiStr, xub_StrLen nLen = STRING_LEN ) const;
bool operator==( const OUString & str ) const BOOL Equals( const UniString& rStr ) const;

BOOL Equals( const sal_Unicode* pCharStr ) const;
bool operator==( "<string literal>" ) const

sal_Bool equalsAscii( const sal_Char* asciiStr ) const SAL_THROW(())

BOOL EqualsAscii( const sal_Char* pAsciiStr ) const;
sal_Bool equalsIgnoreAsciiCase( const OUString & str ) const SAL_THROW(());

sal_Bool equalsIgnoreAsciiCase( "<string literal>" ) const SAL_THROW(());

sal_Bool equalsIgnoreAsciiCaseAscii( const sal_Char * asciiStr ) const SAL_THROW(());

BOOL EqualsIgnoreCaseAscii( const UniString& rStr ) const;

BOOL EqualsIgnoreCaseAscii( const sal_Unicode* pCharStr ) const;

BOOL EqualsIgnoreCaseAscii( const sal_Char* pAsciiStr ) const;

BOOL Equals( const UniString& rStr, xub_StrLen nIndex, xub_StrLen nLen ) const; Please handle those multi-parameter variants with care.

BOOL Equals( const sal_Unicode* pCharStr, xub_StrLen nIndex, xub_StrLen nLen ) const;

BOOL EqualsAscii( const sal_Char* pAsciiStr, xub_StrLen nIndex, xub_StrLen nLen ) const; Please handle those multi-parameter variants with care.

BOOL EqualsIgnoreCaseAscii( const UniString& rStr, xub_StrLen nIndex, xub_StrLen nLen ) const; Please handle those multi-parameter variants with care. For example: EqualsIgnoreCaseAscii( "Simplex", 0, 7 ), where 7 is the length of "Simplex" would be startsWithIgnoreAsciiCase("Simplex").

BOOL EqualsIgnoreCaseAscii( const sal_Unicode* pCharStr, xub_StrLen nIndex, xub_StrLen nLen ) const;

BOOL EqualsIgnoreCaseAscii( const sal_Char* pAsciiStr, xub_StrLen nIndex, xub_StrLen nLen ) const;
bool startsWith( const OUString& str ) const xub_StrLen Match( const UniString& rStr ) const; Match() returns the length of the match, while match() returns a boolean true/false. Substitute with GREAT care! In particular, Match() returns a non-zero (TRUE) value on PARTIAL MATCHES, while match() returns a true value ONLY on FULL MATCHES. So, "oustring.match(foo)" is equivalent to "foo.GetLen() == unistring.Match(foo)". Do NOT replace an isolated "unistring.Match(foo)" by "oustring.match(foo)"!!!

xub_StrLen Match( const sal_Unicode* pCharStr ) const;
sal_Int32 indexOf( sal_Unicode ch, sal_Int32 fromIndex = 0 ) const SAL_THROW(()) xub_StrLen Search( sal_Unicode c, xub_StrLen nIndex = 0 ) const; check for not found with "!= -1" instead of "< USHRT_MAX"
sal_Int32 indexOf( const OUString & str, sal_Int32 fromIndex = 0 ) const SAL_THROW(()) xub_StrLen Search( const UniString& rStr, xub_StrLen nIndex = 0 ) const;

xub_StrLen Search( const sal_Unicode* pCharStr, xub_StrLen nIndex = 0 ) const;
sal_Int32 indexOf( "<string literal>", sal_Int32 fromIndex = 0) const SAL_THROW(()) xub_StrLen SearchAscii( const sal_Char* pAsciiStr, xub_StrLen nIndex = 0 ) const;

sal_Int32 lastIndexOf( sal_Unicode ch, sal_Int32 fromIndex ) const SAL_THROW(())

sal_Int32 lastIndexOf( sal_Unicode ch ) const SAL_THROW(())

xub_StrLen SearchBackward( sal_Unicode c, xub_StrLen nIndex = STRING_LEN ) const;

xub_StrLen SearchChar( const sal_Unicode* pChars, xub_StrLen nIndex = 0 ) const;

xub_StrLen SearchCharBackward( const sal_Unicode* pChars, xub_StrLen nIndex = STRING_LEN ) const;

xub_StrLen SearchAndReplace( sal_Unicode c, sal_Unicode cRep, xub_StrLen nIndex = 0 );
OUString replaceFirst(OUString const & from, OUString const & to, sal_Int32 * index = 0) const xub_StrLen SearchAndReplace( const UniString& rStr, const UniString& rRepStr, xub_StrLen nIndex = 0 ); The OUString function does not modify the object but returns a modified copy.

xub_StrLen SearchAndReplace( const sal_Unicode* pCharStr, const UniString& rRepStr, xub_StrLen nIndex = 0 );

xub_StrLen SearchAndReplaceAscii( const sal_Char* pAsciiStr, const UniString& rRepStr, xub_StrLen nIndex = 0 );

void SearchAndReplaceAll( sal_Unicode c, sal_Unicode cRep );
OUString replaceAll(OUString const & from, OUString const & to, sal_Int32 fromIndex = 0) const void SearchAndReplaceAll( const UniString& rStr, const UniString& rRepStr ); The OUString function does not modify the object but returns a modified copy.

void SearchAndReplaceAll( const sal_Unicode* pCharStr, const UniString& rRepStr );

void SearchAndReplaceAllAscii( const sal_Char* pAsciiStr, const UniString& rRepStr );

xub_StrLen GetTokenCount( sal_Unicode cTok = ';' ) const;

void SetToken( xub_StrLen nToken, sal_Unicode cTok, const UniString& rStr, xub_StrLen nIndex = 0 );
OUString getToken( sal_Int32 token, sal_Unicode cTok, sal_Int32& index ) const SAL_THROW(()) UniString GetToken( xub_StrLen nToken, sal_Unicode cTok, xub_StrLen& rIndex ) const;

UniString GetToken( xub_StrLen nToken, sal_Unicode cTok = ';' ) const;

xub_StrLen GetQuotedTokenCount( const UniString& rQuotedPairs, sal_Unicode cTok = ';' ) const;

UniString GetQuotedToken( xub_StrLen nToken, const UniString& rQuotedPairs, sal_Unicode cTok, xub_StrLen& rIndex ) const;

UniString GetQuotedToken( xub_StrLen nToken, const UniString& rQuotedPairs, sal_Unicode cTok = ';' ) const;
const sal_Unicode * getStr() const SAL_THROW(()) const sal_Unicode* GetBuffer() const;

sal_Unicode* GetBufferAccess();

void ReleaseBufferAccess( xub_StrLen nLen = STRING_LEN );

sal_Unicode* AllocBuffer( xub_StrLen nLen );
friend sal_Bool operator == ( const OUString& rStr1, const OUString& rStr2 ) SAL_THROW(()) friend BOOL operator == ( const UniString& rStr1, const UniString& rStr2 ) { return rStr1.Equals( rStr2 ); }
friend sal_Bool operator != ( const OUString& rStr1, const OUString& rStr2 ) SAL_THROW(()) friend BOOL operator != ( const UniString& rStr1, const UniString& rStr2 ) { return !(operator == ( rStr1, rStr2 )); }
friend sal_Bool operator < ( const OUString& rStr1, const OUString& rStr2 ) SAL_THROW(()) friend BOOL operator < ( const UniString& rStr1, const UniString& rStr2 ) { return (rStr1.CompareTo( rStr2 ) == COMPARE_LESS); }
friend sal_Bool operator > ( const OUString& rStr1, const OUString& rStr2 ) SAL_THROW(()) friend BOOL operator > ( const UniString& rStr1, const UniString& rStr2 ) { return (rStr1.CompareTo( rStr2 ) == COMPARE_GREATER); }
friend sal_Bool operator <= ( const OUString& rStr1, const OUString& rStr2 ) SAL_THROW(()) friend BOOL operator <= ( const UniString& rStr1, const UniString& rStr2 ) { return !(operator > ( rStr1, rStr2 )); }
friend sal_Bool operator >= ( const OUString& rStr1, const OUString& rStr2 ) SAL_THROW(()) friend BOOL operator >= ( const UniString& rStr1, const UniString& rStr2 ) { return !(operator < ( rStr1, rStr2 )); }