LCOV - code coverage report
Current view: top level - comphelper/source/misc - string.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 197 242 81.4 %
Date: 2014-04-11 Functions: 27 29 93.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include "sal/config.h"
      21             : 
      22             : #include <cstddef>
      23             : #include <string.h>
      24             : #include <vector>
      25             : #include <algorithm>
      26             : 
      27             : #include <rtl/ustring.hxx>
      28             : #include <rtl/ustrbuf.hxx>
      29             : #include <rtl/string.hxx>
      30             : #include <rtl/strbuf.hxx>
      31             : #include <sal/types.h>
      32             : 
      33             : #include <comphelper/string.hxx>
      34             : #include <comphelper/stl_types.hxx>
      35             : 
      36             : #include <com/sun/star/i18n/BreakIterator.hpp>
      37             : #include <com/sun/star/i18n/CharType.hpp>
      38             : #include <com/sun/star/i18n/Collator.hpp>
      39             : 
      40             : 
      41             : namespace comphelper { namespace string {
      42             : 
      43             : namespace
      44             : {
      45       10608 :     template <typename T, typename C> T tmpl_stripStart(const T &rIn,
      46             :         const C cRemove)
      47             :     {
      48       10608 :         if (rIn.isEmpty())
      49          13 :             return rIn;
      50             : 
      51       10595 :         sal_Int32 i = 0;
      52             : 
      53       22869 :         while (i < rIn.getLength())
      54             :         {
      55       12270 :             if (rIn[i] != cRemove)
      56       10591 :                 break;
      57        1679 :             ++i;
      58             :         }
      59             : 
      60       10595 :         return rIn.copy(i);
      61             :     }
      62             : }
      63             : 
      64        1874 : OString stripStart(const OString &rIn, sal_Char c)
      65             : {
      66        1874 :     return tmpl_stripStart<OString, sal_Char>(rIn, c);
      67             : }
      68             : 
      69        8734 : OUString stripStart(const OUString &rIn, sal_Unicode c)
      70             : {
      71        8734 :     return tmpl_stripStart<OUString, sal_Unicode>(rIn, c);
      72             : }
      73             : 
      74             : namespace
      75             : {
      76       21142 :     template <typename T, typename C> T tmpl_stripEnd(const T &rIn,
      77             :         const C cRemove)
      78             :     {
      79       21142 :         if (rIn.isEmpty())
      80          58 :             return rIn;
      81             : 
      82       21084 :         sal_Int32 i = rIn.getLength();
      83             : 
      84       44434 :         while (i > 0)
      85             :         {
      86       23145 :             if (rIn[i-1] != cRemove)
      87       20879 :                 break;
      88        2266 :             --i;
      89             :         }
      90             : 
      91       21084 :         return rIn.copy(0, i);
      92             :     }
      93             : }
      94             : 
      95         272 : OString stripEnd(const OString &rIn, sal_Char c)
      96             : {
      97         272 :     return tmpl_stripEnd<OString, sal_Char>(rIn, c);
      98             : }
      99             : 
     100       20870 : OUString stripEnd(const OUString &rIn, sal_Unicode c)
     101             : {
     102       20870 :     return tmpl_stripEnd<OUString, sal_Unicode>(rIn, c);
     103             : }
     104             : 
     105         268 : OString strip(const OString &rIn, sal_Char c)
     106             : {
     107         268 :     return stripEnd(stripStart(rIn, c), c);
     108             : }
     109             : 
     110        8140 : OUString strip(const OUString &rIn, sal_Unicode c)
     111             : {
     112        8140 :     return stripEnd(stripStart(rIn, c), c);
     113             : }
     114             : 
     115             : namespace
     116             : {
     117      134392 :     template <typename T, typename C> sal_Int32 tmpl_getTokenCount(const T &rIn,
     118             :         C cTok)
     119             :     {
     120             :         // Empty String: TokenCount by Definition is 0
     121      134392 :         if (rIn.isEmpty())
     122          21 :             return 0;
     123             : 
     124      134371 :         sal_Int32 nTokCount = 1;
     125     2157356 :         for (sal_Int32 i = 0; i < rIn.getLength(); ++i)
     126             :         {
     127     2022985 :             if (rIn[i] == cTok)
     128       56621 :                 ++nTokCount;
     129             :         }
     130      134371 :         return nTokCount;
     131             :     }
     132             : }
     133             : 
     134      131454 : sal_Int32 getTokenCount(const OString &rIn, sal_Char cTok)
     135             : {
     136      131454 :     return tmpl_getTokenCount<OString, sal_Char>(rIn, cTok);
     137             : }
     138             : 
     139        2938 : sal_Int32 getTokenCount(const OUString &rIn, sal_Unicode cTok)
     140             : {
     141        2938 :     return tmpl_getTokenCount<OUString, sal_Unicode>(rIn, cTok);
     142             : }
     143             : 
     144      172613 : sal_uInt32 decimalStringToNumber(
     145             :     OUString const & str )
     146             : {
     147      172613 :     sal_uInt32 result = 0;
     148      522079 :     for( sal_Int32 i = 0 ; i < str.getLength() ; )
     149             :     {
     150      176853 :         sal_uInt32 c = str.iterateCodePoints(&i);
     151      176853 :         sal_uInt32 value = 0;
     152      176853 :         if( c <= 0x0039)    // ASCII decimal digits, most common
     153      176850 :             value = c - 0x0030;
     154           3 :         else if( c >= 0x1D7F6 )    // mathematical monospace digits
     155           2 :             value = c - 0x1D7F6;
     156           1 :         else if( c >= 0x1D7EC ) // mathematical sans-serif bold digits
     157           0 :             value = c - 0x1D7EC;
     158           1 :         else if( c >= 0x1D7E2 ) // mathematical sans-serif digits
     159           0 :             value = c - 0x1D7E2;
     160           1 :         else if( c >= 0x1D7D8 ) // mathematical double-struck digits
     161           0 :             value = c - 0x1D7D8;
     162           1 :         else if( c >= 0x1D7CE ) // mathematical bold digits
     163           0 :             value = c - 0x1D7CE;
     164           1 :         else if( c >= 0x11066 ) // brahmi digits
     165           0 :             value = c - 0x11066;
     166           1 :         else if( c >= 0x104A0 ) // osmanya digits
     167           0 :             value = c - 0x104A0;
     168           1 :         else if( c >= 0xFF10 ) // fullwidth digits
     169           0 :             value = c - 0xFF10;
     170           1 :         else if( c >= 0xABF0 ) // meetei mayek digits
     171           0 :             value = c - 0xABF0;
     172           1 :         else if( c >= 0xAA50 ) // cham digits
     173           0 :             value = c - 0xAA50;
     174           1 :         else if( c >= 0xA9D0 ) // javanese digits
     175           0 :             value = c - 0xA9D0;
     176           1 :         else if( c >= 0xA900 ) // kayah li digits
     177           0 :             value = c - 0xA900;
     178           1 :         else if( c >= 0xA8D0 ) // saurashtra digits
     179           0 :             value = c - 0xA8D0;
     180           1 :         else if( c >= 0xA620 ) // vai digits
     181           0 :             value = c - 0xA620;
     182           1 :         else if( c >= 0x1C50 ) // ol chiki digits
     183           0 :             value = c - 0x1C50;
     184           1 :         else if( c >= 0x1C40 ) // lepcha digits
     185           0 :             value = c - 0x1C40;
     186           1 :         else if( c >= 0x1BB0 ) // sundanese digits
     187           0 :             value = c - 0x1BB0;
     188           1 :         else if( c >= 0x1B50 ) // balinese digits
     189           0 :             value = c - 0x1B50;
     190           1 :         else if( c >= 0x1A90 ) // tai tham tham digits
     191           0 :             value = c - 0x1A90;
     192           1 :         else if( c >= 0x1A80 ) // tai tham hora digits
     193           0 :             value = c - 0x1A80;
     194           1 :         else if( c >= 0x19D0 ) // new tai lue digits
     195           0 :             value = c - 0x19D0;
     196           1 :         else if( c >= 0x1946 ) // limbu digits
     197           0 :             value = c - 0x1946;
     198           1 :         else if( c >= 0x1810 ) // mongolian digits
     199           0 :             value = c - 0x1810;
     200           1 :         else if( c >= 0x17E0 ) // khmer digits
     201           0 :             value = c - 0x17E0;
     202           1 :         else if( c >= 0x1090 ) // myanmar shan digits
     203           0 :             value = c - 0x1090;
     204           1 :         else if( c >= 0x1040 ) // myanmar digits
     205           0 :             value = c - 0x1040;
     206           1 :         else if( c >= 0x0F20 ) // tibetan digits
     207           0 :             value = c - 0x0F20;
     208           1 :         else if( c >= 0x0ED0 ) // lao digits
     209           0 :             value = c - 0x0ED0;
     210           1 :         else if( c >= 0x0E50 ) // thai digits
     211           0 :             value = c - 0x0E50;
     212           1 :         else if( c >= 0x0D66 ) // malayalam digits
     213           0 :             value = c - 0x0D66;
     214           1 :         else if( c >= 0x0CE6 ) // kannada digits
     215           0 :             value = c - 0x0CE6;
     216           1 :         else if( c >= 0x0C66 ) // telugu digits
     217           0 :             value = c - 0x0C66;
     218           1 :         else if( c >= 0x0BE6 ) // tamil digits
     219           0 :             value = c - 0x0BE6;
     220           1 :         else if( c >= 0x0B66 ) // odia digits
     221           0 :             value = c - 0x0B66;
     222           1 :         else if( c >= 0x0AE6 ) // gujarati digits
     223           0 :             value = c - 0x0AE6;
     224           1 :         else if( c >= 0x0A66 ) // gurmukhi digits
     225           0 :             value = c - 0x0A66;
     226           1 :         else if( c >= 0x09E6 ) // bengali digits
     227           0 :             value = c - 0x09E6;
     228           1 :         else if( c >= 0x0966 ) // devanagari digit
     229           0 :             value = c - 0x0966;
     230           1 :         else if( c >= 0x07C0 ) // nko digits
     231           1 :             value = c - 0x07C0;
     232           0 :         else if( c >= 0x06F0 ) // extended arabic-indic digits
     233           0 :             value = c - 0x06F0;
     234           0 :         else if( c >= 0x0660 ) // arabic-indic digits
     235           0 :             value = c - 0x0660;
     236      176853 :         result = result * 10 + value;
     237             :     }
     238      172613 :     return result;
     239             : }
     240             : 
     241             : using namespace ::com::sun::star;
     242             : 
     243             : // convert between sequence of string and comma separated string
     244             : 
     245          82 : OUString convertCommaSeparated(
     246             :     uno::Sequence< OUString > const& i_rSeq)
     247             : {
     248          82 :     OUStringBuffer buf;
     249             :     ::comphelper::intersperse(
     250          82 :         i_rSeq.begin(), i_rSeq.end(), ::comphelper::OUStringBufferAppender(buf), OUString( ", " ));
     251          82 :     return buf.makeStringAndClear();
     252             : }
     253             : 
     254             : uno::Sequence< OUString >
     255          64 :     convertCommaSeparated( OUString const& i_rString )
     256             : {
     257          64 :     std::vector< OUString > vec;
     258          64 :     sal_Int32 idx = 0;
     259          67 :     do {
     260             :       OUString kw =
     261          67 :         i_rString.getToken(0, static_cast<sal_Unicode> (','), idx);
     262          67 :       kw = kw.trim();
     263          67 :       if (!kw.isEmpty()) {
     264           6 :           vec.push_back(kw);
     265          67 :       }
     266          67 :     } while (idx >= 0);
     267          64 :     uno::Sequence< OUString > kws(vec.size());
     268          64 :     std::copy(vec.begin(), vec.end(), kws.begin());
     269          64 :     return kws;
     270             : }
     271             : 
     272             : 
     273      591661 : sal_Int32 compareNatural( const OUString & rLHS, const OUString & rRHS,
     274             :     const uno::Reference< i18n::XCollator > &rCollator,
     275             :     const uno::Reference< i18n::XBreakIterator > &rBI,
     276             :     const lang::Locale &rLocale )
     277             : {
     278      591661 :     sal_Int32 nRet = 0;
     279             : 
     280      591661 :     sal_Int32 nLHSLastNonDigitPos = 0;
     281      591661 :     sal_Int32 nRHSLastNonDigitPos = 0;
     282      591661 :     sal_Int32 nLHSFirstDigitPos = 0;
     283      591661 :     sal_Int32 nRHSFirstDigitPos = 0;
     284             : 
     285     1199668 :     while (nLHSFirstDigitPos < rLHS.getLength() || nRHSFirstDigitPos < rRHS.getLength())
     286             :     {
     287             :         sal_Int32 nLHSChunkLen;
     288             :         sal_Int32 nRHSChunkLen;
     289             : 
     290             :         //Compare non digit block as normal strings
     291      608005 :         nLHSFirstDigitPos = rBI->nextCharBlock(rLHS, nLHSLastNonDigitPos,
     292      608005 :             rLocale, i18n::CharType::DECIMAL_DIGIT_NUMBER);
     293      608005 :         nRHSFirstDigitPos = rBI->nextCharBlock(rRHS, nRHSLastNonDigitPos,
     294      608005 :             rLocale, i18n::CharType::DECIMAL_DIGIT_NUMBER);
     295      608005 :         if (nLHSFirstDigitPos == -1)
     296      186915 :             nLHSFirstDigitPos = rLHS.getLength();
     297      608005 :         if (nRHSFirstDigitPos == -1)
     298      275589 :             nRHSFirstDigitPos = rRHS.getLength();
     299      608005 :         nLHSChunkLen = nLHSFirstDigitPos - nLHSLastNonDigitPos;
     300      608005 :         nRHSChunkLen = nRHSFirstDigitPos - nRHSLastNonDigitPos;
     301             : 
     302      608005 :         nRet = rCollator->compareSubstring(rLHS, nLHSLastNonDigitPos,
     303      608005 :             nLHSChunkLen, rRHS, nRHSLastNonDigitPos, nRHSChunkLen);
     304      608005 :         if (nRet != 0)
     305      521700 :             break;
     306             : 
     307             :         //Compare digit block as one number vs another
     308       86305 :         nLHSLastNonDigitPos = rBI->endOfCharBlock(rLHS, nLHSFirstDigitPos,
     309       86305 :             rLocale, i18n::CharType::DECIMAL_DIGIT_NUMBER);
     310       86305 :         nRHSLastNonDigitPos = rBI->endOfCharBlock(rRHS, nRHSFirstDigitPos,
     311       86305 :             rLocale, i18n::CharType::DECIMAL_DIGIT_NUMBER);
     312       86305 :         if (nLHSLastNonDigitPos == -1)
     313          26 :             nLHSLastNonDigitPos = rLHS.getLength();
     314       86305 :         if (nRHSLastNonDigitPos == -1)
     315          10 :             nRHSLastNonDigitPos = rRHS.getLength();
     316       86305 :         nLHSChunkLen = nLHSLastNonDigitPos - nLHSFirstDigitPos;
     317       86305 :         nRHSChunkLen = nRHSLastNonDigitPos - nRHSFirstDigitPos;
     318             : 
     319             :         //To-Do: Possibly scale down those unicode codepoints that relate to
     320             :         //numbers outside of the normal 0-9 range, e.g. see GetLocalizedChar in
     321             :         //vcl
     322             : 
     323       86305 :         sal_uInt32 nLHS = comphelper::string::decimalStringToNumber(rLHS.copy(nLHSFirstDigitPos, nLHSChunkLen));
     324       86305 :         sal_uInt32 nRHS = comphelper::string::decimalStringToNumber(rRHS.copy(nRHSFirstDigitPos, nRHSChunkLen));
     325             : 
     326       86305 :         nRet = nLHS-nRHS;
     327       86305 :         if (nRet != 0)
     328       69959 :             break;
     329             :     }
     330             : 
     331             :     //Squeeze these down to -1, 0, 1 in case there is an assumption those are
     332             :     //the only valid returns
     333      591661 :     if (nRet > 0)
     334      472618 :         nRet = 1;
     335      119043 :     else if (nRet < 0)
     336      119041 :         nRet = -1;
     337             : 
     338      591661 :     return nRet;
     339             : }
     340             : 
     341         307 : NaturalStringSorter::NaturalStringSorter(
     342             :     const uno::Reference< uno::XComponentContext > &rContext,
     343         307 :     const lang::Locale &rLocale) : m_aLocale(rLocale)
     344             : {
     345         307 :     m_xCollator = i18n::Collator::create( rContext );
     346         307 :     m_xCollator->loadDefaultCollator(m_aLocale, 0);
     347         307 :     m_xBI = i18n::BreakIterator::create( rContext );
     348         307 : }
     349             : 
     350             : namespace
     351             : {
     352             :     //do OPER on each element of the string, return false
     353             :     //if any OPER is false, true otherwise
     354             :     template <bool (*OPER)(sal_Unicode), typename T>
     355         804 :     bool tmpl_is_OPER_AsciiString(const T &rString)
     356             :     {
     357        3411 :         for (sal_Int32 i = 0; i < rString.getLength(); ++i)
     358             :         {
     359        2726 :             if (!OPER(rString[i]))
     360         119 :                 return false;
     361             :         }
     362         685 :         return true;
     363             :     }
     364             : }
     365             : 
     366         804 : bool isdigitAsciiString(const OString &rString)
     367             : {
     368         804 :     return tmpl_is_OPER_AsciiString<isdigitAscii>(rString);
     369             : }
     370             : 
     371           0 : bool isdigitAsciiString(const OUString &rString)
     372             : {
     373           0 :     return tmpl_is_OPER_AsciiString<isdigitAscii>(rString);
     374             : }
     375             : 
     376             : namespace
     377             : {
     378         517 :     template <typename T, typename O> T tmpl_reverseString(const T &rIn)
     379             :     {
     380         517 :         if (rIn.isEmpty())
     381           0 :             return rIn;
     382             : 
     383         517 :         sal_Int32 i = rIn.getLength();
     384         517 :         O sBuf(i);
     385        2559 :         while (i)
     386        1525 :             sBuf.append(rIn[--i]);
     387         517 :         return sBuf.makeStringAndClear();
     388             :     }
     389             : }
     390             : 
     391         516 : OUString reverseString(const OUString &rStr)
     392             : {
     393         516 :     return tmpl_reverseString<OUString, OUStringBuffer>(rStr);
     394             : }
     395             : 
     396           1 : OString reverseString(const OString &rStr)
     397             : {
     398           1 :     return tmpl_reverseString<OString, OStringBuffer>(rStr);
     399             : }
     400             : 
     401         619 : sal_Int32 indexOfAny(OUString const& rIn,
     402             :         sal_Unicode const*const pChars, sal_Int32 const nPos)
     403             : {
     404       25896 :     for (sal_Int32 i = nPos; i < rIn.getLength(); ++i)
     405             :     {
     406       25286 :         sal_Unicode const c = rIn[i];
     407      101039 :         for (sal_Unicode const* pChar = pChars; *pChar; ++pChar)
     408             :         {
     409       75762 :             if (c == *pChar)
     410             :             {
     411           9 :                 return i;
     412             :             }
     413             :         }
     414             :     }
     415         610 :     return -1;
     416             : }
     417             : 
     418         582 : OUString setToken(const OUString& rIn, sal_Int32 nToken, sal_Unicode cTok,
     419             :     const OUString& rNewToken)
     420             : {
     421         582 :     const sal_Unicode* pStr = rIn.getStr();
     422         582 :     sal_Int32 nLen = rIn.getLength();
     423         582 :     sal_Int32 nTok = 0;
     424         582 :     sal_Int32 nFirstChar = 0;
     425         582 :     sal_Int32 i = 0;
     426             : 
     427             :     // Determine token position and length
     428       15115 :     while ( i < nLen )
     429             :     {
     430             :         // Increase token count if match
     431       14511 :         if (*pStr == cTok)
     432             :         {
     433        8940 :             ++nTok;
     434             : 
     435        8940 :             if (nTok == nToken)
     436         546 :                 nFirstChar = i+1;
     437        8394 :             else if (nTok > nToken)
     438         560 :                 break;
     439             :         }
     440             : 
     441             :         ++pStr,
     442       13951 :         ++i;
     443             :     }
     444             : 
     445         582 :     if (nTok >= nToken)
     446         582 :         return rIn.replaceAt(nFirstChar, i-nFirstChar, rNewToken);
     447           0 :     return rIn;
     448             : }
     449             : 
     450             : } }
     451             : 
     452             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10