Added IntlCodePointBreakIterator.

Objects of this class can be instantiated with

IntlBreakIterator::createCodePointInstance()

The method does not take a locale, as it would not make sense in this
context.

This class has one additional method:

long IntlCodePointIterator::getLastCodePoint()

which returns either -1 or the last code point we moved over, if any
(and discounting any movement before the last call to
IntlBreakIterator::first() or IntlBreakIterator::last()).
This commit is contained in:
Gustavo André dos Santos Lopes 2012-06-22 18:19:54 +02:00
parent cee31091a9
commit 0a7ae87e91
15 changed files with 736 additions and 2 deletions

View File

@ -20,6 +20,7 @@
#include <unicode/brkiter.h>
#include <unicode/rbbi.h>
#include "codepointiterator_internal.h"
#include "breakiterator_iterators.h"
@ -30,14 +31,18 @@ extern "C" {
#include "breakiterator_class.h"
#include "breakiterator_methods.h"
#include "rulebasedbreakiterator_methods.h"
#include "codepointiterator_methods.h"
#include <zend_exceptions.h>
#include <zend_interfaces.h>
#include <assert.h>
}
using PHP::CodePointBreakIterator;
/* {{{ Global variables */
zend_class_entry *BreakIterator_ce_ptr;
zend_class_entry *RuleBasedBreakIterator_ce_ptr;
zend_class_entry *CodePointBreakIterator_ce_ptr;
zend_object_handlers BreakIterator_handlers;
/* }}} */
@ -49,6 +54,8 @@ U_CFUNC void breakiterator_object_create(zval *object,
if (classId == RuleBasedBreakIterator::getStaticClassID()) {
ce = RuleBasedBreakIterator_ce_ptr;
} else if (classId == CodePointBreakIterator::getStaticClassID()) {
ce = CodePointBreakIterator_ce_ptr;
} else {
ce = BreakIterator_ce_ptr;
}
@ -274,6 +281,7 @@ static const zend_function_entry BreakIterator_class_functions[] = {
PHP_ME_MAPPING(createCharacterInstance, breakiter_create_character_instance, ainfo_biter_locale, ZEND_ACC_STATIC | ZEND_ACC_PUBLIC)
PHP_ME_MAPPING(createSentenceInstance, breakiter_create_sentence_instance, ainfo_biter_locale, ZEND_ACC_STATIC | ZEND_ACC_PUBLIC)
PHP_ME_MAPPING(createTitleInstance, breakiter_create_title_instance, ainfo_biter_locale, ZEND_ACC_STATIC | ZEND_ACC_PUBLIC)
PHP_ME_MAPPING(createCodePointInstance, breakiter_create_code_point_instance, ainfo_biter_void, ZEND_ACC_STATIC | ZEND_ACC_PUBLIC)
PHP_ME_MAPPING(getText, breakiter_get_text, ainfo_biter_void, ZEND_ACC_PUBLIC)
PHP_ME_MAPPING(setText, breakiter_set_text, ainfo_biter_setText, ZEND_ACC_PUBLIC)
PHP_ME_MAPPING(first, breakiter_first, ainfo_biter_void, ZEND_ACC_PUBLIC)
@ -305,6 +313,14 @@ static const zend_function_entry RuleBasedBreakIterator_class_functions[] = {
};
/* }}} */
/* {{{ CodePointBreakIterator_class_functions
*/
static const zend_function_entry CodePointBreakIterator_class_functions[] = {
PHP_ME_MAPPING(getLastCodePoint, cpbi_get_last_code_point, ainfo_biter_void, ZEND_ACC_PUBLIC)
PHP_FE_END
};
/* }}} */
/* {{{ breakiterator_register_BreakIterator_class
* Initialize 'BreakIterator' class
@ -364,6 +380,12 @@ void breakiterator_register_BreakIterator_class(TSRMLS_D)
INIT_CLASS_ENTRY(ce, "IntlRuleBasedBreakIterator",
RuleBasedBreakIterator_class_functions);
RuleBasedBreakIterator_ce_ptr = zend_register_internal_class_ex(&ce,
BreakIterator_ce_ptr, NULL TSRMLS_CC);
BreakIterator_ce_ptr, NULL TSRMLS_CC);
/* Create and register 'CodePointBreakIterator' class. */
INIT_CLASS_ENTRY(ce, "IntlCodePointBreakIterator",
CodePointBreakIterator_class_functions);
CodePointBreakIterator_ce_ptr = zend_register_internal_class_ex(&ce,
BreakIterator_ce_ptr, NULL TSRMLS_CC);
}
/* }}} */

View File

@ -19,6 +19,7 @@
#endif
#include <unicode/brkiter.h>
#include "codepointiterator_internal.h"
#include "breakiterator_iterators.h"
@ -29,6 +30,8 @@ extern "C" {
#include <zend_exceptions.h>
}
using PHP::CodePointBreakIterator;
U_CFUNC PHP_METHOD(BreakIterator, __construct)
{
zend_throw_exception( NULL,
@ -107,6 +110,21 @@ U_CFUNC PHP_FUNCTION(breakiter_create_title_instance)
INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
U_CFUNC PHP_FUNCTION(breakiter_create_code_point_instance)
{
UErrorCode status = UErrorCode();
intl_error_reset(NULL TSRMLS_CC);
if (zend_parse_parameters_none() == FAILURE) {
intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
"breakiter_create_code_point_instance: bad arguments", 0 TSRMLS_CC);
RETURN_NULL();
}
CodePointBreakIterator *cpbi = new CodePointBreakIterator();
breakiterator_object_create(return_value, cpbi TSRMLS_CC);
}
U_CFUNC PHP_FUNCTION(breakiter_get_text)
{
BREAKITER_METHOD_INIT_VARS;

View File

@ -31,6 +31,8 @@ PHP_FUNCTION(breakiter_create_sentence_instance);
PHP_FUNCTION(breakiter_create_title_instance);
PHP_FUNCTION(breakiter_create_code_point_instance);
PHP_FUNCTION(breakiter_get_text);
PHP_FUNCTION(breakiter_set_text);

View File

@ -0,0 +1,286 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Gustavo Lopes <cataphract@php.net> |
+----------------------------------------------------------------------+
*/
#include "codepointiterator_internal.h"
#include <unicode/uchriter.h>
//copied from cmemory.h, which is not public
typedef union {
long t1;
double t2;
void *t3;
} UAlignedMemory;
#define U_POINTER_MASK_LSB(ptr, mask) (((ptrdiff_t)(char *)(ptr)) & (mask))
#define U_ALIGNMENT_OFFSET(ptr) U_POINTER_MASK_LSB(ptr, sizeof(UAlignedMemory) - 1)
#define U_ALIGNMENT_OFFSET_UP(ptr) (sizeof(UAlignedMemory) - U_ALIGNMENT_OFFSET(ptr))
using namespace PHP;
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CodePointBreakIterator);
CodePointBreakIterator::CodePointBreakIterator()
: BreakIterator(), fCharIter(NULL), lastCodePoint(U_SENTINEL)
{
UErrorCode uec = UErrorCode();
this->fText = utext_openUChars(NULL, NULL, 0, &uec);
}
CodePointBreakIterator::CodePointBreakIterator(const PHP::CodePointBreakIterator &other)
: BreakIterator(other), fText(NULL), fCharIter(NULL), lastCodePoint(U_SENTINEL)
{
*this = other;
}
CodePointBreakIterator& CodePointBreakIterator::operator=(const CodePointBreakIterator& that)
{
UErrorCode uec = UErrorCode();
UText *ut_clone = NULL;
if (this == &that) {
return *this;
}
this->fText = utext_clone(this->fText, that.fText, FALSE, TRUE, &uec);
//don't bother copying the character iterator, getText() is deprecated
clearCurrentCharIter();
this->lastCodePoint = that.lastCodePoint;
return *this;
}
CodePointBreakIterator::~CodePointBreakIterator()
{
if (this->fText) {
utext_close(this->fText);
}
clearCurrentCharIter();
}
UBool CodePointBreakIterator::operator==(const BreakIterator& that) const
{
if (typeid(*this) != typeid(that)) {
return FALSE;
}
const CodePointBreakIterator& that2 =
static_cast<const CodePointBreakIterator&>(that);
if (!utext_equals(this->fText, that2.fText)) {
return FALSE;
}
return TRUE;
}
CodePointBreakIterator* CodePointBreakIterator::clone(void) const
{
return new CodePointBreakIterator(*this);
}
CharacterIterator& CodePointBreakIterator::getText(void) const
{
if (this->fCharIter == NULL) {
//this method is deprecated anyway; setup bogus iterator
static const UChar c = 0;
this->fCharIter = new UCharCharacterIterator(&c, 0);
}
return *this->fCharIter;
}
UText *CodePointBreakIterator::getUText(UText *fillIn, UErrorCode &status) const
{
return utext_clone(fillIn, this->fText, FALSE, TRUE, &status);
}
void CodePointBreakIterator::setText(const UnicodeString &text)
{
UErrorCode uec = UErrorCode();
//this closes the previous utext, if any
this->fText = utext_openConstUnicodeString(this->fText, &text, &uec);
clearCurrentCharIter();
}
void CodePointBreakIterator::setText(UText *text, UErrorCode &status)
{
if (U_FAILURE(status)) {
return;
}
this->fText = utext_clone(this->fText, text, FALSE, TRUE, &status);
clearCurrentCharIter();
}
void CodePointBreakIterator::adoptText(CharacterIterator* it)
{
UErrorCode uec = UErrorCode();
clearCurrentCharIter();
this->fCharIter = it;
this->fText = utext_openCharacterIterator(this->fText, it, &uec);
}
int32_t CodePointBreakIterator::first(void)
{
UTEXT_SETNATIVEINDEX(this->fText, 0);
this->lastCodePoint = U_SENTINEL;
return 0;
}
int32_t CodePointBreakIterator::last(void)
{
int32_t pos = (int32_t)utext_nativeLength(this->fText);
UTEXT_SETNATIVEINDEX(this->fText, pos);
this->lastCodePoint = U_SENTINEL;
return pos;
}
int32_t CodePointBreakIterator::previous(void)
{
this->lastCodePoint = UTEXT_PREVIOUS32(this->fText);
if (this->lastCodePoint == U_SENTINEL) {
return BreakIterator::DONE;
}
return (int32_t)UTEXT_GETNATIVEINDEX(this->fText);
}
int32_t CodePointBreakIterator::next(void)
{
this->lastCodePoint = UTEXT_NEXT32(this->fText);
if (this->lastCodePoint == U_SENTINEL) {
return BreakIterator::DONE;
}
return (int32_t)UTEXT_GETNATIVEINDEX(this->fText);
}
int32_t CodePointBreakIterator::current(void) const
{
return (int32_t)UTEXT_GETNATIVEINDEX(this->fText);
}
int32_t CodePointBreakIterator::following(int32_t offset)
{
this->lastCodePoint = utext_next32From(this->fText, offset);
if (this->lastCodePoint == U_SENTINEL) {
return BreakIterator::DONE;
}
return (int32_t)UTEXT_GETNATIVEINDEX(this->fText);
}
int32_t CodePointBreakIterator::preceding(int32_t offset)
{
this->lastCodePoint = utext_previous32From(this->fText, offset);
if (this->lastCodePoint == U_SENTINEL) {
return BreakIterator::DONE;
}
return (int32_t)UTEXT_GETNATIVEINDEX(this->fText);
}
UBool CodePointBreakIterator::isBoundary(int32_t offset)
{
//this function has side effects, and it's supposed to
utext_setNativeIndex(this->fText, offset);
return (offset == utext_getNativeIndex(this->fText));
}
int32_t CodePointBreakIterator::next(int32_t n)
{
UBool res = utext_moveIndex32(this->fText, n);
if (res) {
this->lastCodePoint = UTEXT_CURRENT32(this->fText);
return (int32_t)UTEXT_GETNATIVEINDEX(this->fText);
} else {
this->lastCodePoint = U_SENTINEL;
return BreakIterator::DONE;
}
}
CodePointBreakIterator *CodePointBreakIterator::createBufferClone(
void *stackBuffer, int32_t &bufferSize, UErrorCode &status)
{
//see implementation of RuleBasedBreakIterator::createBufferClone()
if (U_FAILURE(status)) {
return NULL;
}
if (bufferSize <= 0) {
bufferSize = sizeof(CodePointBreakIterator) + U_ALIGNMENT_OFFSET_UP(0);
return NULL;
}
char *buf = (char*)stackBuffer;
uint32_t s = bufferSize;
if (stackBuffer == NULL) {
s = 0;
}
if (U_ALIGNMENT_OFFSET(stackBuffer) != 0) {
uint32_t offsetUp = (uint32_t)U_ALIGNMENT_OFFSET_UP(buf);
s -= offsetUp;
buf += offsetUp;
}
if (s < sizeof(CodePointBreakIterator)) {
CodePointBreakIterator *clonedBI = new CodePointBreakIterator(*this);
if (clonedBI == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
} else {
status = U_SAFECLONE_ALLOCATED_WARNING;
}
return clonedBI;
}
return new(buf) CodePointBreakIterator(*this);
}
CodePointBreakIterator &CodePointBreakIterator::refreshInputText(UText *input, UErrorCode &status)
{
//see implementation of RuleBasedBreakIterator::createBufferClone()
if (U_FAILURE(status)) {
return *this;
}
if (input == NULL) {
status = U_ILLEGAL_ARGUMENT_ERROR;
return *this;
}
int64_t pos = utext_getNativeIndex(this->fText);
this->fText = utext_clone(this->fText, input, FALSE, TRUE, &status);
if (U_FAILURE(status)) {
return *this;
}
utext_setNativeIndex(this->fText, pos);
if (utext_getNativeIndex(fText) != pos) {
status = U_ILLEGAL_ARGUMENT_ERROR;
}
return *this;
}

View File

@ -0,0 +1,98 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Gustavo Lopes <cataphract@php.net> |
+----------------------------------------------------------------------+
*/
#ifndef CODEPOINTITERATOR_INTERNAL_H
#define CODEPOINTITERATOR_INTERNAL_H
#include <unicode/brkiter.h>
using U_ICU_NAMESPACE::BreakIterator;
namespace PHP {
class CodePointBreakIterator : public BreakIterator {
public:
static UClassID getStaticClassID();
CodePointBreakIterator();
CodePointBreakIterator(const CodePointBreakIterator &other);
CodePointBreakIterator& operator=(const CodePointBreakIterator& that);
virtual ~CodePointBreakIterator();
virtual UBool operator==(const BreakIterator& that) const;
virtual CodePointBreakIterator* clone(void) const;
virtual UClassID getDynamicClassID(void) const;
virtual CharacterIterator& getText(void) const;
virtual UText *getUText(UText *fillIn, UErrorCode &status) const;
virtual void setText(const UnicodeString &text);
virtual void setText(UText *text, UErrorCode &status);
virtual void adoptText(CharacterIterator* it);
virtual int32_t first(void);
virtual int32_t last(void);
virtual int32_t previous(void);
virtual int32_t next(void);
virtual int32_t current(void) const;
virtual int32_t following(int32_t offset);
virtual int32_t preceding(int32_t offset);
virtual UBool isBoundary(int32_t offset);
virtual int32_t next(int32_t n);
virtual CodePointBreakIterator *createBufferClone(void *stackBuffer,
int32_t &BufferSize,
UErrorCode &status);
virtual CodePointBreakIterator &refreshInputText(UText *input, UErrorCode &status);
inline UChar32 getLastCodePoint()
{
return this->lastCodePoint;
}
private:
UText *fText;
UChar32 lastCodePoint;
mutable CharacterIterator *fCharIter;
inline void clearCurrentCharIter()
{
delete this->fCharIter;
this->fCharIter = NULL;
this->lastCodePoint = U_SENTINEL;
}
};
}
#endif

View File

@ -0,0 +1,44 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Gustavo Lopes <cataphract@php.net> |
+----------------------------------------------------------------------+
*/
#include "codepointiterator_internal.h"
extern "C" {
#define USE_BREAKITERATOR_POINTER 1
#include "breakiterator_class.h"
}
using PHP::CodePointBreakIterator;
static inline CodePointBreakIterator *fetch_cpbi(BreakIterator_object *bio) {
return (CodePointBreakIterator*)bio->biter;
}
U_CFUNC PHP_FUNCTION(cpbi_get_last_code_point)
{
BREAKITER_METHOD_INIT_VARS;
object = getThis();
if (zend_parse_parameters_none() == FAILURE) {
intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
"cpbi_get_last_code_point: bad arguments", 0 TSRMLS_CC);
RETURN_FALSE;
}
BREAKITER_METHOD_FETCH_OBJECT;
RETURN_LONG(fetch_cpbi(bio)->getLastCodePoint());
}

View File

@ -0,0 +1,24 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Gustavo Lopes <cataphract@php.net> |
+----------------------------------------------------------------------+
*/
#ifndef CODEPOINTITERATOR_METHODS_H
#define CODEPOINTITERATOR_METHODS_H
#include <php.h>
PHP_FUNCTION(cpbi_get_last_code_point);
#endif

View File

@ -79,6 +79,8 @@ if test "$PHP_INTL" != "no"; then
breakiterator/breakiterator_iterators.cpp \
breakiterator/breakiterator_methods.cpp \
breakiterator/rulebasedbreakiterator_methods.cpp \
breakiterator/codepointiterator_internal.cpp \
breakiterator/codepointiterator_methods.cpp \
idn/idn.c \
$icu_spoof_src, $ext_shared,,$ICU_INCS -Wno-write-strings)
PHP_ADD_BUILD_DIR($ext_builddir/collator)
@ -95,4 +97,5 @@ if test "$PHP_INTL" != "no"; then
PHP_ADD_BUILD_DIR($ext_builddir/calendar)
PHP_ADD_BUILD_DIR($ext_builddir/idn)
PHP_ADD_BUILD_DIR($ext_builddir/spoofchecker)
PHP_ADD_BUILD_DIR($ext_builddir/breakiterator)
fi

View File

@ -107,7 +107,9 @@ if (PHP_INTL != "no") {
breakiterator_class.cpp \
breakiterator_methods.cpp \
breakiterator_iterators.cpp \
rulebasedbreakiterator_methods.cpp",
rulebasedbreakiterator_methods.cpp \
codepointiterator_internal.cpp \
codepointiterator_methods.cpp ",
"intl");
ADD_FLAG("LIBS_INTL", "icudt.lib icuin.lib icuio.lib icule.lib iculx.lib");

View File

@ -0,0 +1,43 @@
--TEST--
IntlBreakIterator::createCodePointInstance(): basic test
--SKIPIF--
<?php
if (!extension_loaded('intl'))
die('skip intl extension not enabled');
--FILE--
<?php
ini_set("intl.error_level", E_WARNING);
ini_set("intl.default_locale", "pt_PT");
$text = 'ตัวอย่างข้อความ';
$codepoint_it = IntlBreakIterator::createCodePointInstance();
var_dump(get_class($codepoint_it));
$codepoint_it->setText($text);
print_r(iterator_to_array($codepoint_it));
?>
==DONE==
--EXPECT--
string(26) "IntlCodePointBreakIterator"
Array
(
[0] => 0
[1] => 3
[2] => 6
[3] => 9
[4] => 12
[5] => 15
[6] => 18
[7] => 21
[8] => 24
[9] => 27
[10] => 30
[11] => 33
[12] => 36
[13] => 39
[14] => 42
[15] => 45
)
==DONE==

View File

@ -0,0 +1,18 @@
--TEST--
IntlBreakIterator::createCodePointInstance(): bad arguments
--SKIPIF--
<?php
if (!extension_loaded('intl'))
die('skip intl extension not enabled');
--FILE--
<?php
ini_set("intl.error_level", E_WARNING);
var_dump(IntlBreakIterator::createCodePointInstance(array()));
--EXPECTF--
Warning: IntlBreakIterator::createCodePointInstance() expects exactly 0 parameters, 1 given in %s on line %d
Warning: IntlBreakIterator::createCodePointInstance(): breakiter_create_code_point_instance: bad arguments in %s on line %d
NULL

View File

@ -0,0 +1,33 @@
--TEST--
IntlCodePointBreakIterator: clone and equality
--SKIPIF--
<?php
if (!extension_loaded('intl'))
die('skip intl extension not enabled');
--FILE--
<?php
ini_set("intl.error_level", E_WARNING);
ini_set("intl.default_locale", "pt_PT");
$text = 'ตัวอย่างข้อความ';
$text2 = 'foo';
$it = IntlBreakIterator::createCodePointInstance();
$it->setText($text);
$it_clone = clone $it;
var_dump($it == $it_clone);
$it->setText($text2 );
var_dump($it == $it_clone);
$it_clone->setText($text2);
var_dump($it == $it_clone);
?>
==DONE==
--EXPECT--
bool(true)
bool(false)
bool(true)
==DONE==

View File

@ -0,0 +1,82 @@
--TEST--
IntlCodepointBreakIterator::getLastCodePoint(): basic test
--SKIPIF--
<?php
if (!extension_loaded('intl'))
die('skip intl extension not enabled');
--FILE--
<?php
ini_set("intl.error_level", E_WARNING);
ini_set("intl.default_locale", "pt_PT");
$text = 'ตัวอย่างข้อความ';
$codepoint_it = IntlBreakIterator::createCodePointInstance();
$codepoint_it->setText($text);
var_dump($codepoint_it->getLastCodePoint());
//first() and last() don't read codepoint and set the last code point var to -1
//The pointer is after the last read codepoint if moving forward and
//before the last read codepoint is moving backwards
$p = $codepoint_it->first();
while ($p != IntlBreakIterator::DONE) {
$c = $codepoint_it->getLastCodePoint();
if ($c > 0)
var_dump(sprintf('U+%04X', $codepoint_it->getLastCodePoint()));
else
var_dump($c);
//it's a post-increment operation as to the codepoint, i.e., it gives the codepoint
//starting at the initial position and only then moves the pointer forward
$p = $codepoint_it->next();
}
echo "Now backwards\n";
$p = $codepoint_it->last();
while ($p != IntlBreakIterator::DONE) {
$c = $codepoint_it->getLastCodePoint();
if ($c > 0)
var_dump(sprintf('U+%04X', $codepoint_it->getLastCodePoint()));
else
var_dump($c);
$p = $codepoint_it->previous();
}
?>
==DONE==
--EXPECT--
int(-1)
int(-1)
string(6) "U+0E15"
string(6) "U+0E31"
string(6) "U+0E27"
string(6) "U+0E2D"
string(6) "U+0E22"
string(6) "U+0E48"
string(6) "U+0E32"
string(6) "U+0E07"
string(6) "U+0E02"
string(6) "U+0E49"
string(6) "U+0E2D"
string(6) "U+0E04"
string(6) "U+0E27"
string(6) "U+0E32"
string(6) "U+0E21"
Now backwards
int(-1)
string(6) "U+0E21"
string(6) "U+0E32"
string(6) "U+0E27"
string(6) "U+0E04"
string(6) "U+0E2D"
string(6) "U+0E49"
string(6) "U+0E02"
string(6) "U+0E07"
string(6) "U+0E32"
string(6) "U+0E48"
string(6) "U+0E22"
string(6) "U+0E2D"
string(6) "U+0E27"
string(6) "U+0E31"
string(6) "U+0E15"
==DONE==

View File

@ -0,0 +1,19 @@
--TEST--
IntlBreakIterator::getLastCodePoint(): bad args
--SKIPIF--
<?php
if (!extension_loaded('intl'))
die('skip intl extension not enabled');
--FILE--
<?php
ini_set("intl.error_level", E_WARNING);
$it = IntlBreakIterator::createCodePointInstance();
var_dump($it->getLastCodePoint(array()));
--EXPECTF--
Warning: IntlCodePointBreakIterator::getLastCodePoint() expects exactly 0 parameters, 1 given in %s on line %d
Warning: IntlCodePointBreakIterator::getLastCodePoint(): cpbi_get_last_code_point: bad arguments in %s on line %d
bool(false)

View File

@ -0,0 +1,40 @@
--TEST--
IntlCodepointBreakIterator's part iterator
--SKIPIF--
<?php
if (!extension_loaded('intl'))
die('skip intl extension not enabled');
--FILE--
<?php
ini_set("intl.error_level", E_WARNING);
ini_set("intl.default_locale", "pt_PT");
$text = 'ตัวอย่างข้อความ';
$it = IntlBreakIterator::createCodePointInstance()->getPartsIterator();
$it->getBreakIterator()->setText($text);
foreach ($it as $k => $v) {
echo "$k. $v (" . sprintf("U+%04X", $it->getBreakIterator()->getLastCodePoint()) .
") at {$it->getBreakIterator()->current()}\r\n";
}
?>
==DONE==
--EXPECT--
0. ต (U+0E15) at 3
1. ั (U+0E31) at 6
2. ว (U+0E27) at 9
3. อ (U+0E2D) at 12
4. ย (U+0E22) at 15
5. ่ (U+0E48) at 18
6. า (U+0E32) at 21
7. ง (U+0E07) at 24
8. ข (U+0E02) at 27
9. ้ (U+0E49) at 30
10. อ (U+0E2D) at 33
11. ค (U+0E04) at 36
12. ว (U+0E27) at 39
13. า (U+0E32) at 42
14. ม (U+0E21) at 45
==DONE==