You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
109 lines
3.0 KiB
109 lines
3.0 KiB
/* |
|
* Copyright (C) 2017 The Android Open Source Project |
|
* |
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
* you may not use this file except in compliance with the License. |
|
* You may obtain a copy of the License at |
|
* |
|
* http://www.apache.org/licenses/LICENSE-2.0 |
|
* |
|
* Unless required by applicable law or agreed to in writing, software |
|
* distributed under the License is distributed on an "AS IS" BASIS, |
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
* See the License for the specific language governing permissions and |
|
* limitations under the License. |
|
*/ |
|
|
|
#include "lang_id/custom-tokenizer.h" |
|
|
|
#include <ctype.h> |
|
|
|
#include <string> |
|
|
|
#include "util/strings/utf8.h" |
|
|
|
namespace libtextclassifier { |
|
namespace nlp_core { |
|
namespace lang_id { |
|
|
|
namespace { |
|
inline bool IsTokenSeparator(int num_bytes, const char *curr) { |
|
if (num_bytes != 1) { |
|
return false; |
|
} |
|
return !isalpha(*curr); |
|
} |
|
} // namespace |
|
|
|
const char *GetSafeEndOfString(const char *data, size_t size) { |
|
const char *const hard_end = data + size; |
|
const char *curr = data; |
|
while (curr < hard_end) { |
|
int num_bytes = GetNumBytesForUTF8Char(curr); |
|
if (num_bytes == 0) { |
|
break; |
|
} |
|
const char *new_curr = curr + num_bytes; |
|
if (new_curr > hard_end) { |
|
return curr; |
|
} |
|
curr = new_curr; |
|
} |
|
return curr; |
|
} |
|
|
|
void TokenizeTextForLangId(const std::string &text, LightSentence *sentence) { |
|
const char *const start = text.data(); |
|
const char *curr = start; |
|
const char *end = GetSafeEndOfString(start, text.size()); |
|
|
|
// Corner case: empty safe part of the text. |
|
if (curr >= end) { |
|
return; |
|
} |
|
|
|
// Number of bytes for UTF8 character starting at *curr. Note: the loop below |
|
// is guaranteed to terminate because in each iteration, we move curr by at |
|
// least num_bytes, and num_bytes is guaranteed to be > 0. |
|
int num_bytes = GetNumBytesForNonZeroUTF8Char(curr); |
|
while (curr < end) { |
|
// Jump over consecutive token separators. |
|
while (IsTokenSeparator(num_bytes, curr)) { |
|
curr += num_bytes; |
|
if (curr >= end) { |
|
return; |
|
} |
|
num_bytes = GetNumBytesForNonZeroUTF8Char(curr); |
|
} |
|
|
|
// If control reaches this point, we are at beginning of a non-empty token. |
|
std::string *word = sentence->add_word(); |
|
|
|
// Add special token-start character. |
|
word->push_back('^'); |
|
|
|
// Add UTF8 characters to word, until we hit the end of the safe text or a |
|
// token separator. |
|
while (true) { |
|
word->append(curr, num_bytes); |
|
curr += num_bytes; |
|
if (curr >= end) { |
|
break; |
|
} |
|
num_bytes = GetNumBytesForNonZeroUTF8Char(curr); |
|
if (IsTokenSeparator(num_bytes, curr)) { |
|
curr += num_bytes; |
|
num_bytes = GetNumBytesForNonZeroUTF8Char(curr); |
|
break; |
|
} |
|
} |
|
word->push_back('$'); |
|
|
|
// Note: we intentionally do not token.set_start()/end(), as those fields |
|
// are not used by the langid model. |
|
} |
|
} |
|
|
|
} // namespace lang_id |
|
} // namespace nlp_core |
|
} // namespace libtextclassifier
|
|
|