LCOV - code coverage report
Current view: top level - queryparser - cjk-tokenizer.cc (source / functions) Hit Total Coverage
Test: Test Coverage for xapian-core fcfb185a9dd5 Lines: 36 36 100.0 %
Date: 2019-04-18 16:33:14 Functions: 6 6 100.0 %
Branches: 24 34 70.6 %

           Branch data     Line data    Source code
       1                 :            : /** @file cjk-tokenizer.cc
       2                 :            :  * @brief Tokenise CJK text as n-grams
       3                 :            :  */
       4                 :            : /* Copyright (c) 2007, 2008 Yung-chung Lin (henearkrxern@gmail.com)
       5                 :            :  * Copyright (c) 2011 Richard Boulton (richard@tartarus.org)
       6                 :            :  * Copyright (c) 2011 Brandon Schaefer (brandontschaefer@gmail.com)
       7                 :            :  * Copyright (c) 2011,2018,2019 Olly Betts
       8                 :            :  *
       9                 :            :  * Permission is hereby granted, free of charge, to any person obtaining a copy
      10                 :            :  * of this software and associated documentation files (the "Software"), to deal
      11                 :            :  * deal in the Software without restriction, including without limitation the
      12                 :            :  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
      13                 :            :  * sell copies of the Software, and to permit persons to whom the Software is
      14                 :            :  * furnished to do so, subject to the following conditions:
      15                 :            :  *
      16                 :            :  * The above copyright notice and this permission notice shall be included in
      17                 :            :  * all copies or substantial portions of the Software.
      18                 :            :  *
      19                 :            :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      20                 :            :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      21                 :            :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      22                 :            :  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      23                 :            :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      24                 :            :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
      25                 :            :  * IN THE SOFTWARE.
      26                 :            :  */
      27                 :            : 
      28                 :            : #include <config.h>
      29                 :            : 
      30                 :            : #include "cjk-tokenizer.h"
      31                 :            : 
      32                 :            : #include "omassert.h"
      33                 :            : #include "xapian/unicode.h"
      34                 :            : #include "xapian/error.h"
      35                 :            : 
      36                 :            : #include <algorithm>
      37                 :            : #include <cstdlib>
      38                 :            : #include <string>
      39                 :            : 
      40                 :            : using namespace std;
      41                 :            : 
      42                 :            : bool
      43                 :      65013 : CJK::is_cjk_enabled()
      44                 :            : {
      45                 :            :     const char * p;
      46 [ +  + ][ +  - ]:      65013 :     static bool result = ((p = getenv("XAPIAN_CJK_NGRAM")) != NULL && *p);
         [ -  + ][ #  # ]
      47                 :      65013 :     return result;
      48                 :            : }
      49                 :            : 
      50                 :            : bool
      51                 :        482 : CJK::codepoint_is_cjk(unsigned p)
      52                 :            : {
      53                 :            :     // Array containing the last value in each range of codepoints which
      54                 :            :     // are either all CJK or all non-CJK.
      55                 :            :     static const unsigned splits[] = {
      56                 :            :         // 1100..11FF; Hangul Jamo
      57                 :            :         0x1100 - 1, 0x11FF,
      58                 :            :         // 2E80..2EFF; CJK Radicals Supplement
      59                 :            :         // 2F00..2FDF; Kangxi Radicals
      60                 :            :         0x2E80 - 1, 0x2FDF,
      61                 :            :         // 3000..303F; CJK Symbols and Punctuation
      62                 :            :         // 3040..309F; Hiragana
      63                 :            :         // 30A0..30FF; Katakana
      64                 :            :         // 3100..312F; Bopomofo
      65                 :            :         // 3130..318F; Hangul Compatibility Jamo
      66                 :            :         // 3190..319F; Kanbun
      67                 :            :         // 31A0..31BF; Bopomofo Extended
      68                 :            :         // 31C0..31EF; CJK Strokes
      69                 :            :         // 31F0..31FF; Katakana Phonetic Extensions
      70                 :            :         // 3200..32FF; Enclosed CJK Letters and Months
      71                 :            :         // 3300..33FF; CJK Compatibility
      72                 :            :         // 3400..4DBF; CJK Unified Ideographs Extension A
      73                 :            :         // 4DC0..4DFF; Yijing Hexagram Symbols
      74                 :            :         // 4E00..9FFF; CJK Unified Ideographs
      75                 :            :         0x3000 - 1, 0x9FFF,
      76                 :            :         // A700..A71F; Modifier Tone Letters
      77                 :            :         0xA700 - 1, 0xA71F,
      78                 :            :         // A960..A97F; Hangul Jamo Extended-A
      79                 :            :         0xA960 - 1, 0xA97F,
      80                 :            :         // AC00..D7AF; Hangul Syllables
      81                 :            :         // D7B0..D7FF; Hangul Jamo Extended-B
      82                 :            :         0xAC00 - 1, 0xD7FF,
      83                 :            :         // F900..FAFF; CJK Compatibility Ideographs
      84                 :            :         0xF900 - 1, 0xFAFF,
      85                 :            :         // FE30..FE4F; CJK Compatibility Forms
      86                 :            :         0xFE30 - 1, 0xFE4F,
      87                 :            :         // FF00..FFEF; Halfwidth and Fullwidth Forms
      88                 :            :         0xFF00 - 1, 0xFFEF,
      89                 :            :         // 1B000..1B0FF; Kana Supplement
      90                 :            :         // 1B100..1B12F; Kana Extended-A
      91                 :            :         0x1B000 - 1, 0x1B12F,
      92                 :            :         // 1F200..1F2FF; Enclosed Ideographic Supplement
      93                 :            :         0x1F200 - 1, 0x1F2FF,
      94                 :            :         // 20000..2A6DF; CJK Unified Ideographs Extension B
      95                 :            :         0x20000 - 1, 0x2A6DF,
      96                 :            :         // 2A700..2B73F; CJK Unified Ideographs Extension C
      97                 :            :         // 2B740..2B81F; CJK Unified Ideographs Extension D
      98                 :            :         // 2B820..2CEAF; CJK Unified Ideographs Extension E
      99                 :            :         // 2CEB0..2EBEF; CJK Unified Ideographs Extension F
     100                 :            :         0x2A700 - 1, 0x2EBEF,
     101                 :            :         // 2F800..2FA1F; CJK Compatibility Ideographs Supplement
     102                 :            :         0x2F800 - 1, 0x2FA1F,
     103                 :            :     };
     104                 :            :     // Binary chop to find the first entry which is >= p.  If it's an odd
     105                 :            :     // offset then the codepoint is CJK; if it's an even offset then it's not.
     106                 :        482 :     auto it = lower_bound(splits, splits + sizeof(splits) / sizeof(*splits), p);
     107                 :        482 :     return ((it - splits) & 1);
     108                 :            : }
     109                 :            : 
     110                 :            : bool
     111                 :        342 : CJK::codepoint_is_cjk_wordchar(unsigned p)
     112                 :            : {
     113 [ +  + ][ +  + ]:        342 :     return codepoint_is_cjk(p) && Xapian::Unicode::is_wordchar(p);
     114                 :            : }
     115                 :            : 
     116                 :            : size_t
     117                 :         31 : CJK::get_cjk(Xapian::Utf8Iterator& it)
     118                 :            : {
     119                 :         31 :     size_t char_count = 0;
     120 [ +  + ][ +  + ]:        192 :     while (it != Xapian::Utf8Iterator() &&
                 [ +  - ]
           [ +  +  #  # ]
     121         [ +  - ]:         91 :            codepoint_is_cjk_wordchar(*it)) {
     122                 :         70 :         ++char_count;
     123                 :         70 :         ++it;
     124                 :            :     }
     125                 :         31 :     return char_count;
     126                 :            : }
     127                 :            : 
     128                 :            : void
     129                 :         51 : CJKNgramIterator::init() {
     130         [ +  - ]:         51 :     if (it != Xapian::Utf8Iterator()) {
     131                 :         51 :         unsigned ch = *it;
     132         [ +  - ]:         51 :         if (CJK::codepoint_is_cjk_wordchar(ch)) {
     133                 :         51 :             Xapian::Unicode::append_utf8(current_token, ch);
     134                 :         51 :             ++it;
     135                 :            :         } else {
     136                 :         51 :             current_token.resize(0);
     137                 :            :         }
     138                 :            :     }
     139                 :         51 : }
     140                 :            : 
     141                 :            : CJKNgramIterator&
     142                 :        379 : CJKNgramIterator::operator++()
     143                 :            : {
     144         [ +  + ]:        379 :     if (offset == 0) {
     145         [ +  + ]:        215 :         if (it != Xapian::Utf8Iterator()) {
     146                 :        170 :             unsigned ch = *it;
     147         [ +  + ]:        170 :             if (CJK::codepoint_is_cjk_wordchar(ch)) {
     148                 :        164 :                 offset = current_token.size();
     149                 :        164 :                 Xapian::Unicode::append_utf8(current_token, ch);
     150                 :        164 :                 ++it;
     151                 :            :             } else {
     152                 :        170 :                 current_token.resize(0);
     153                 :            :             }
     154                 :            :         } else {
     155                 :        215 :             current_token.resize(0);
     156                 :            :         }
     157                 :            :     } else {
     158                 :        164 :         current_token.erase(0, offset);
     159                 :        164 :         offset = 0;
     160                 :            :     }
     161                 :        379 :     return *this;
     162                 :            : }
     163                 :            : 
     164                 :            : #ifdef USE_ICU
     165                 :            : CJKWordIterator::CJKWordIterator(const char* ptr, size_t len)
     166                 :            : {
     167                 :            :     UErrorCode err = U_ZERO_ERROR;
     168                 :            :     UText utext = UTEXT_INITIALIZER;
     169                 :            :     brk = icu::BreakIterator::createWordInstance(0/*unknown locale*/, err);
     170                 :            :     if (usual(U_SUCCESS(err))) {
     171                 :            :         utext_openUTF8(&utext, ptr, len, &err);
     172                 :            :         if (usual(U_SUCCESS(err)))
     173                 :            :             brk->setText(&utext, err);
     174                 :            :         utext_close(&utext);
     175                 :            :     }
     176                 :            :     if (rare(U_FAILURE(err)))
     177                 :            :         throw Xapian::InternalError(string("ICU error: ") + u_errorName(err));
     178                 :            :     int32_t first = brk->first();
     179                 :            :     p = brk->next();
     180                 :            :     utf8_ptr = ptr;
     181                 :            :     current_token.assign(utf8_ptr + first, p - first);
     182                 :            : }
     183                 :            : 
     184                 :            : CJKWordIterator &
     185                 :            : CJKWordIterator::operator++()
     186                 :            : {
     187                 :            :     int32_t first = p;
     188                 :            :     p = brk->next();
     189                 :            :     if (usual(p != done)) {
     190                 :            :         current_token.assign(utf8_ptr + first, p - first);
     191                 :            :     }
     192                 :            :     return *this;
     193                 :            : }
     194                 :            : #endif

Generated by: LCOV version 1.11