15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef BASE_I18N_BREAK_ITERATOR_H_
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define BASE_I18N_BREAK_ITERATOR_H_
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/i18n/base_i18n_export.h"
10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string16.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The BreakIterator class iterates through the words, word breaks, and
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// line breaks in a UTF-16 string.
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// It provides several modes, BREAK_WORD, BREAK_LINE, and BREAK_NEWLINE,
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// which modify how characters are aggregated into the returned string.
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Under BREAK_WORD mode, once a word is encountered any non-word
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// characters are not included in the returned string (e.g. in the
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// UTF-16 equivalent of the string " foo bar! ", the word breaks are at
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the periods in ". .foo. .bar.!. .").
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note that Chinese/Japanese/Thai do not use spaces between words so that
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// boundaries can fall in the middle of a continuous run of non-space /
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// non-punctuation characters.
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Under BREAK_LINE mode, once a line breaking opportunity is encountered,
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// any non-word  characters are included in the returned string, breaking
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// only when a space-equivalent character or a line breaking opportunity
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// is encountered (e.g. in the UTF16-equivalent of the string " foo bar! ",
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the breaks are at the periods in ". .foo .bar! .").
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note that lines can be broken at any character/syllable/grapheme cluster
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// boundary in Chinese/Japanese/Korean and at word boundaries in Thai
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// (Thai does not use spaces between words). Therefore, this is NOT the same
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// as breaking only at space-equivalent characters where its former
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// name (BREAK_SPACE) implied.
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Under BREAK_NEWLINE mode, all characters are included in the returned
394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// string, breaking only when a newline-equivalent character is encountered
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// (eg. in the UTF-16 equivalent of the string "foo\nbar!\n\n", the line
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// breaks are at the periods in ".foo\n.bar\n.\n.").
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// To extract the words from a string, move a BREAK_WORD BreakIterator
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// through the string and test whether IsWord() is true. E.g.,
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   BreakIterator iter(str, BreakIterator::BREAK_WORD);
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   if (!iter.Init())
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     return false;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   while (iter.Advance()) {
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     if (iter.IsWord()) {
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//       // Region [iter.prev(), iter.pos()) contains a word.
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//       VLOG(1) << "word: " << iter.GetString();
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     }
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   }
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace base {
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace i18n {
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class BASE_I18N_EXPORT BreakIterator {
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  enum BreakType {
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BREAK_WORD,
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BREAK_LINE,
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(jshin): Remove this after reviewing call sites.
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If call sites really need break only on space-like characters
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // implement it separately.
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BREAK_SPACE = BREAK_LINE,
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BREAK_NEWLINE,
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BREAK_CHARACTER,
69f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // But don't remove this one!
70f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    RULE_BASED,
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Requires |str| to live as long as the BreakIterator does.
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BreakIterator(const string16& str, BreakType break_type);
75f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Make a rule-based iterator. BreakType == RULE_BASED is implied.
76f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // TODO(andrewhayden): This signature could easily be misinterpreted as
77f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // "(const string16& str, const string16& locale)". We should do something
78f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // better.
79f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  BreakIterator(const string16& str, const string16& rules);
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~BreakIterator();
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Init() must be called before any of the iterators are valid.
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns false if ICU failed to initialize.
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool Init();
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Advance to the next break.  Returns false if we've run past the end of
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the string.  (Note that the very last "break" is after the final
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // character in the string, and when we advance to that position it's the
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // last time Advance() returns true.)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool Advance();
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
92f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Updates the text used by the iterator, resetting the iterator as if
93f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // if Init() had been called again. Any old state is lost. Returns true
94f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // unless there is an error setting the text.
95f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  bool SetText(const base::char16* text, const size_t length);
96f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Under BREAK_WORD mode, returns true if the break we just hit is the
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // end of a word. (Otherwise, the break iterator just skipped over e.g.
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // whitespace or punctuation.)  Under BREAK_LINE and BREAK_NEWLINE modes,
1004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // this distinction doesn't apply and it always returns false.
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool IsWord() const;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Under BREAK_WORD mode, returns true if |position| is at the end of word or
1044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // at the start of word. It always returns false under BREAK_LINE and
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // BREAK_NEWLINE modes.
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool IsEndOfWord(size_t position) const;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool IsStartOfWord(size_t position) const;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Under BREAK_CHARACTER mode, returns whether |position| is a Unicode
1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // grapheme boundary.
1115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  bool IsGraphemeBoundary(size_t position) const;
1125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns the string between prev() and pos().
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Advance() must have been called successfully at least once for pos() to
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // have advanced to somewhere useful.
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  string16 GetString() const;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns the value of pos() returned before Advance() was last called.
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t prev() const { return prev_; }
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns the current break position within the string,
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // or BreakIterator::npos when done.
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t pos() const { return pos_; }
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ICU iterator, avoiding ICU ubrk.h dependence.
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This is actually an ICU UBreakiterator* type, which turns out to be
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a typedef for a void* in the ICU headers. Using void* directly prevents
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // callers from needing access to the ICU public headers directory.
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void* iter_;
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
132f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // The string we're iterating over. Can be changed with SetText(...)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const string16& string_;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Rules for our iterator. Mutually exclusive with break_type_.
136f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const string16 rules_;
137f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
138f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // The breaking style (word/space/newline). Mutually exclusive with rules_
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BreakType break_type_;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Previous and current iterator positions.
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t prev_, pos_;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(BreakIterator);
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace i18n
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace base
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // BASE_I18N_BREAK_ITERATOR_H_
151