/********************************************************************
* COPYRIGHT:
- * Copyright (c) 2002-2010, International Business Machines Corporation and
+ * Copyright (c) 2002-2015, International Business Machines Corporation and
* others. All Rights Reserved.
********************************************************************/
// ICU Regular Expressions test, part of intltest.
//
+/*
+ NOTE!!
+
+ PLEASE be careful about ASCII assumptions in this test.
+ This test is one of the worst repeat offenders.
+ If you have questions, contact someone on the ICU PMC
+ who has access to an EBCDIC system.
+
+ */
+
#include "intltest.h"
#if !UCONFIG_NO_REGULAR_EXPRESSIONS
+#include "unicode/localpointer.h"
#include "unicode/regex.h"
#include "unicode/uchar.h"
#include "unicode/ucnv.h"
+#include "unicode/uniset.h"
+#include "unicode/uregex.h"
+#include "unicode/usetiter.h"
#include "unicode/ustring.h"
#include "regextst.h"
+#include "regexcmp.h"
#include "uvector.h"
#include "util.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
+#include "cmemory.h"
#include "cstring.h"
#include "uinvchar.h"
case 17: name = "Bug 7740";
if (exec) Bug7740();
break;
-
+ case 18: name = "Bug 8479";
+ if (exec) Bug8479();
+ break;
+ case 19: name = "Bug 7029";
+ if (exec) Bug7029();
+ break;
+ case 20: name = "CheckInvBufSize";
+ if (exec) CheckInvBufSize();
+ break;
+ case 21: name = "Bug 9283";
+ if (exec) Bug9283();
+ break;
+ case 22: name = "Bug10459";
+ if (exec) Bug10459();
+ break;
+ case 23: name = "TestCaseInsensitiveStarters";
+ if (exec) TestCaseInsensitiveStarters();
+ break;
+ case 24: name = "TestBug11049";
+ if (exec) TestBug11049();
+ break;
+ case 25: name = "TestBug11371";
+ if (exec) TestBug11371();
+ break;
+ case 26: name = "TestBug11480";
+ if (exec) TestBug11480();
+ break;
+ case 27: name = "NamedCapture";
+ if (exec) NamedCapture();
+ break;
+ case 28: name = "NamedCaptureLimits";
+ if (exec) NamedCaptureLimits();
+ break;
default: name = "";
break; //needed to end loop
}
}
+
/**
* Calls utext_openUTF8 after, potentially, converting invariant text from the compilation codepage
- * into ASCII.
+ * into ASCII.
* @see utext_openUTF8
*/
static UText* regextst_openUTF8FromInvariant(UText* ut, const char *inv, int64_t length, UErrorCode *status);
-static UText* regextst_openUTF8FromInvariant(UText *ut, const char *inv, int64_t length, UErrorCode *status) {
-#if U_CHARSET_FAMILY==U_ASCII_FAMILY
- return utext_openUTF8(ut, inv, length, status);
-#else
- char buf[1024];
-
- uprv_aestrncpy((uint8_t*)buf, (const uint8_t*)inv, length);
-
- return utext_openUTF8(ut, buf, length, status);
-#endif
-}
-
//---------------------------------------------------------------------------
//
// Error Checking / Reporting macros used in all of the tests.
utext_setNativeIndex(text, oldIndex);
}
+
+static char ASSERT_BUF[1024];
+
+const char* RegexTest::extractToAssertBuf(const UnicodeString& message) {
+ if(message.length()==0) {
+ strcpy(ASSERT_BUF, "[[empty UnicodeString]]");
+ } else {
+ UnicodeString buf;
+ IntlTest::prettify(message,buf);
+ if(buf.length()==0) {
+ strcpy(ASSERT_BUF, "[[escape() returned 0 chars]]");
+ } else {
+ buf.extract(0, 0x7FFFFFFF, ASSERT_BUF, sizeof(ASSERT_BUF)-1);
+ if(ASSERT_BUF[0]==0) {
+ ASSERT_BUF[0]=0;
+ for(int32_t i=0;i<buf.length();i++) {
+ UChar ch = buf[i];
+ sprintf(ASSERT_BUF+strlen(ASSERT_BUF),"\\u%02x",ch);
+ }
+ }
+ }
+ }
+ ASSERT_BUF[sizeof(ASSERT_BUF)-1] = 0;
+ return ASSERT_BUF;
+}
+
#define REGEX_VERBOSE_TEXT(text) {char buf[200];utextToPrintable(buf,sizeof(buf)/sizeof(buf[0]),text);logln("%s:%d: UText %s=\"%s\"", __FILE__, __LINE__, #text, buf);}
#define REGEX_CHECK_STATUS {if (U_FAILURE(status)) {dataerrln("%s:%d: RegexTest failure. status=%s", \
#define REGEX_ASSERT_L(expr, line) {if ((expr)==FALSE) { \
errln("RegexTest failure at line %d, from %d.", __LINE__, (line)); return;}}
+// expected: const char * , restricted to invariant characters.
+// actual: const UnicodeString &
+#define REGEX_ASSERT_UNISTR(expected, actual) { \
+ if (UnicodeString(expected, -1, US_INV) != (actual)) { \
+ errln("%s:%d: RegexTest failure: REGEX_ASSERT_UNISTR(%s, %s) failed \n", \
+ __FILE__, __LINE__, expected, extractToAssertBuf(actual));};}
+
+
+static UBool testUTextEqual(UText *uta, UText *utb) {
+ UChar32 ca = 0;
+ UChar32 cb = 0;
+ utext_setNativeIndex(uta, 0);
+ utext_setNativeIndex(utb, 0);
+ do {
+ ca = utext_next32(uta);
+ cb = utext_next32(utb);
+ if (ca != cb) {
+ break;
+ }
+ } while (ca != U_SENTINEL);
+ return ca == cb;
+}
+
+
/**
* @param expected expected text in UTF-8 (not platform) codepage
*/
return;
}
utext_setNativeIndex(actual, 0);
- if (utext_compare(&expectedText, -1, actual, -1) != 0) {
+ if (!testUTextEqual(&expectedText, actual)) {
char buf[201 /*21*/];
char expectedBuf[201];
utextToPrintable(buf, sizeof(buf)/sizeof(buf[0]), actual);
return;
}
utext_setNativeIndex(actual, 0);
- if (utext_compare(&expectedText, -1, actual, -1) != 0) {
+ if (!testUTextEqual(&expectedText, actual)) {
char buf[201 /*21*/];
char expectedBuf[201];
utextToPrintable(buf, sizeof(buf)/sizeof(buf[0]), actual);
}
/**
- * Assumes utf-8 input
+ * Assumes utf-8 input
*/
#define REGEX_ASSERT_UTEXT_UTF8(expected, actual) assertUText((expected), (actual), __FILE__, __LINE__)
/**
- * Assumes Invariant input
+ * Assumes Invariant input
*/
#define REGEX_ASSERT_UTEXT_INVARIANT(expected, actual) assertUTextInvariant((expected), (actual), __FILE__, __LINE__)
+/**
+ * This buffer ( inv_buf ) is used to hold the UTF-8 strings
+ * passed into utext_openUTF8. An error will be given if
+ * INV_BUFSIZ is too small. It's only used on EBCDIC systems.
+ */
+
+#define INV_BUFSIZ 2048 /* increase this if too small */
+
+static int64_t inv_next=0;
+
+#if U_CHARSET_FAMILY!=U_ASCII_FAMILY
+static char inv_buf[INV_BUFSIZ];
+#endif
+
+static UText* regextst_openUTF8FromInvariant(UText *ut, const char *inv, int64_t length, UErrorCode *status) {
+ if(length==-1) length=strlen(inv);
+#if U_CHARSET_FAMILY==U_ASCII_FAMILY
+ inv_next+=length;
+ return utext_openUTF8(ut, inv, length, status);
+#else
+ if(inv_next+length+1>INV_BUFSIZ) {
+ fprintf(stderr, "%s:%d Error: INV_BUFSIZ #defined to be %d but needs to be at least %d.\n",
+ __FILE__, __LINE__, INV_BUFSIZ, (inv_next+length+1));
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+
+ unsigned char *buf = (unsigned char*)inv_buf+inv_next;
+ uprv_aestrncpy(buf, (const uint8_t*)inv, length);
+ inv_next+=length;
+
+#if 0
+ fprintf(stderr, " Note: INV_BUFSIZ at %d, used=%d\n", INV_BUFSIZ, inv_next);
+#endif
+
+ return utext_openUTF8(ut, (const char*)buf, length, status);
+#endif
+}
+
//---------------------------------------------------------------------------
//
line, u_errorName(status));
return FALSE;
}
- if (line==376) { RegexPatternDump(REPattern);}
+ if (line==376) { REPattern->dumpPattern();}
UnicodeString inputString(inputText);
UnicodeString unEscapedInput = inputString.unescape();
}
if (retVal == FALSE) {
- RegexPatternDump(REPattern);
+ REPattern->dumpPattern();
}
delete REPattern;
line, u_errorName(status));
return FALSE;
}
-
+
UnicodeString inputString(text, -1, US_INV);
UnicodeString unEscapedInput = inputString.unescape();
LocalUConverterPointer UTF8Converter(ucnv_open("UTF8", &status));
ucnv_setFromUCallBack(UTF8Converter.getAlias(), UCNV_FROM_U_CALLBACK_STOP, NULL, NULL, NULL, &status);
-
+
inputUTF8Length = unEscapedInput.extract(NULL, 0, UTF8Converter.getAlias(), status);
if (U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR) {
// UTF-8 does not allow unpaired surrogates, so this could actually happen
textChars = new char[inputUTF8Length+1];
unEscapedInput.extract(textChars, inputUTF8Length+1, UTF8Converter.getAlias(), status);
utext_openUTF8(&inputText, textChars, inputUTF8Length, &status);
-
- REMatcher = REPattern->matcher(&inputText, RegexPattern::PATTERN_IS_UTEXT, status);
+
+ REMatcher = &REPattern->matcher(status)->reset(&inputText);
if (U_FAILURE(status)) {
errln("RegexTest failure in REPattern::matcher() at line %d (UTF8). Status = %s\n",
line, u_errorName(status));
}
if (retVal == FALSE) {
- RegexPatternDump(REPattern);
+ REPattern->dumpPattern();
}
delete REPattern;
}
}
}
-
+
delete callerPattern;
utext_close(&patternText);
}
// REGEX_TESTLM("a\N{LATIN SMALL LETTER B}c", "abc", FALSE, FALSE);
UParseError pe;
UErrorCode status = U_ZERO_ERROR;
- RegexPattern::compile("^(?:a?b?)*$", 0, pe, status);
- // REGEX_FIND("(?>(abc{2,4}?))(c*)", "<0>ab<1>cc</1><2>ccc</2></0>ddd");
+ RegexPattern *pattern;
+ pattern = RegexPattern::compile(UNICODE_STRING_SIMPLE("a\\u00dfx").unescape(), UREGEX_CASE_INSENSITIVE, pe, status);
+ pattern->dumpPattern();
+ RegexMatcher *m = pattern->matcher(UNICODE_STRING_SIMPLE("a\\u00dfxzzz").unescape(), status);
+ UBool result = m->find();
+ printf("result = %d\n", result);
+ // REGEX_FIND("", "<0>ab<1>cc</1><2>ccc</2></0>ddd");
// REGEX_FIND("(X([abc=X]+)+X)|(y[abc=]+)", "=XX====================");
}
exit(1);
utext_openUTF8(&pattern, str_abc, -1, &status);
RegexMatcher matcher(&pattern, 0, status);
REGEX_CHECK_STATUS;
-
+
UText input = UTEXT_INITIALIZER;
utext_openUTF8(&input, str_abc, -1, &status);
REGEX_CHECK_STATUS;
matcher.reset(&input);
REGEX_CHECK_STATUS;
REGEX_ASSERT_UTEXT_UTF8(str_abc, matcher.inputText());
-
+
matcher.reset(matcher.inputText());
REGEX_CHECK_STATUS;
REGEX_ASSERT_UTEXT_UTF8(str_abc, matcher.inputText());
-
+
utext_close(&pattern);
utext_close(&input);
}
delete m;
delete p;
}
-
+
//
// Regions
//
REGEX_ASSERT(m.regionEnd() == testString.length());
REGEX_ASSERT(m.hasTransparentBounds() == FALSE);
REGEX_ASSERT(m.hasAnchoringBounds() == TRUE);
-
+
m.region(2,4, status);
REGEX_CHECK_STATUS;
REGEX_ASSERT(m.matches(status));
REGEX_ASSERT(m.start(status)==2);
REGEX_ASSERT(m.end(status)==4);
REGEX_CHECK_STATUS;
-
+
m.reset();
REGEX_ASSERT(m.regionStart() == 0);
REGEX_ASSERT(m.regionEnd() == testString.length());
-
+
UnicodeString shorterString("short");
m.reset(shorterString);
REGEX_ASSERT(m.regionStart() == 0);
REGEX_ASSERT(m.regionEnd() == shorterString.length());
-
+
REGEX_ASSERT(m.hasAnchoringBounds() == TRUE);
REGEX_ASSERT(&m == &m.useAnchoringBounds(FALSE));
REGEX_ASSERT(m.hasAnchoringBounds() == FALSE);
REGEX_ASSERT(&m == &m.reset());
REGEX_ASSERT(m.hasAnchoringBounds() == FALSE);
-
+
REGEX_ASSERT(&m == &m.useAnchoringBounds(TRUE));
REGEX_ASSERT(m.hasAnchoringBounds() == TRUE);
REGEX_ASSERT(&m == &m.reset());
REGEX_ASSERT(m.hasAnchoringBounds() == TRUE);
-
+
REGEX_ASSERT(m.hasTransparentBounds() == FALSE);
REGEX_ASSERT(&m == &m.useTransparentBounds(TRUE));
REGEX_ASSERT(m.hasTransparentBounds() == TRUE);
REGEX_ASSERT(m.hasTransparentBounds() == FALSE);
REGEX_ASSERT(&m == &m.reset());
REGEX_ASSERT(m.hasTransparentBounds() == FALSE);
-
+
}
-
+
//
// hitEnd() and requireEnd()
//
REGEX_ASSERT(m1.hitEnd() == TRUE);
REGEX_ASSERT(m1.requireEnd() == FALSE);
REGEX_CHECK_STATUS;
-
+
status = U_ZERO_ERROR;
RegexMatcher m2("a*", testString, 0, status);
REGEX_ASSERT(m2.lookingAt(status) == TRUE);
#endif
//
- // Time Outs.
+ // Time Outs.
// Note: These tests will need to be changed when the regexp engine is
// able to detect and cut short the exponential time behavior on
// this type of match.
REGEX_ASSERT(matcher.lookingAt(status) == FALSE);
REGEX_CHECK_STATUS;
}
-
+
//
// Stack Limits
//
{
UErrorCode status = U_ZERO_ERROR;
UnicodeString testString(1000000, 0x41, 1000000); // Length 1,000,000, filled with 'A'
-
+
// Adding the capturing parentheses to the pattern "(A)+A$" inhibits optimizations
// of the '+', and makes the stack frames larger.
RegexMatcher matcher("(A)+A$", testString, 0, status);
-
+
// With the default stack, this match should fail to run
REGEX_ASSERT(matcher.lookingAt(status) == FALSE);
REGEX_ASSERT(status == U_REGEX_STACK_OVERFLOW);
-
+
// With unlimited stack, it should run
status = U_ZERO_ERROR;
matcher.setStackLimit(0, status);
REGEX_ASSERT(status == U_REGEX_STACK_OVERFLOW);
REGEX_ASSERT(matcher.getStackLimit() == 10000);
}
-
+
// A pattern that doesn't save state should work with
// a minimal sized stack
{
REGEX_ASSERT(matcher.matches(status) == TRUE);
REGEX_CHECK_STATUS;
REGEX_ASSERT(matcher.getStackLimit() == 30);
-
+
// Negative stack sizes should fail
status = U_ZERO_ERROR;
matcher.setStackLimit(1000, status);
REGEX_ASSERT(status == U_ILLEGAL_ARGUMENT_ERROR);
REGEX_ASSERT(matcher.getStackLimit() == 1000);
}
-
+
}
REGEX_ASSERT(dest == "The value of $1 is bc.defg");
dest = matcher2->replaceFirst("$ by itself, no group number $$$", status);
- REGEX_CHECK_STATUS;
- REGEX_ASSERT(dest == "$ by itself, no group number $$$defg");
+ REGEX_ASSERT(U_FAILURE(status));
+ status = U_ZERO_ERROR;
UnicodeString replacement = UNICODE_STRING_SIMPLE("Supplemental Digit 1 $\\U0001D7CF.");
replacement = replacement.unescape();
n = pat1->split(" Now is the time ", fields, 10, status);
REGEX_CHECK_STATUS;
- REGEX_ASSERT(n==5);
+ REGEX_ASSERT(n==6);
REGEX_ASSERT(fields[0]=="");
REGEX_ASSERT(fields[1]=="Now");
REGEX_ASSERT(fields[2]=="is");
n = pat1->split(" ", fields, 10, status);
REGEX_CHECK_STATUS;
- REGEX_ASSERT(n==1);
+ REGEX_ASSERT(n==2);
REGEX_ASSERT(fields[0]=="");
+ REGEX_ASSERT(fields[1]=="");
fields[0] = "foo";
n = pat1->split("", fields, 10, status);
status = U_ZERO_ERROR;
n = pat1->split("<a>Now is <b>the time<c>", fields, 10, status);
REGEX_CHECK_STATUS;
- REGEX_ASSERT(n==6);
+ REGEX_ASSERT(n==7);
REGEX_ASSERT(fields[0]=="");
REGEX_ASSERT(fields[1]=="a");
REGEX_ASSERT(fields[2]=="Now is ");
n = pat1->split(" <a>Now is <b>the time<c>", fields, 10, status);
REGEX_CHECK_STATUS;
- REGEX_ASSERT(n==6);
+ REGEX_ASSERT(n==7);
REGEX_ASSERT(fields[0]==" ");
REGEX_ASSERT(fields[1]=="a");
REGEX_ASSERT(fields[2]=="Now is ");
REGEX_ASSERT(fields[2]=="Now is ");
REGEX_ASSERT(fields[3]=="b");
REGEX_ASSERT(fields[4]=="the time");
- REGEX_ASSERT(fields[5]=="c");
+ REGEX_ASSERT(fields[5]==""); // All text following "<c>" field delimiter.
REGEX_ASSERT(fields[6]=="foo");
status = U_ZERO_ERROR;
REGEX_ASSERT(fields[4]=="20");
delete pat1;
+ // Test split of string with empty trailing fields
+ pat1 = RegexPattern::compile(",", pe, status);
+ REGEX_CHECK_STATUS;
+ n = pat1->split("a,b,c,", fields, 10, status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(n==4);
+ REGEX_ASSERT(fields[0]=="a");
+ REGEX_ASSERT(fields[1]=="b");
+ REGEX_ASSERT(fields[2]=="c");
+ REGEX_ASSERT(fields[3]=="");
+
+ n = pat1->split("a,,,", fields, 10, status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(n==4);
+ REGEX_ASSERT(fields[0]=="a");
+ REGEX_ASSERT(fields[1]=="");
+ REGEX_ASSERT(fields[2]=="");
+ REGEX_ASSERT(fields[3]=="");
+ delete pat1;
+
+ // Split Separator with zero length match.
+ pat1 = RegexPattern::compile(":?", pe, status);
+ REGEX_CHECK_STATUS;
+ n = pat1->split("abc", fields, 10, status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(n==5);
+ REGEX_ASSERT(fields[0]=="");
+ REGEX_ASSERT(fields[1]=="a");
+ REGEX_ASSERT(fields[2]=="b");
+ REGEX_ASSERT(fields[3]=="c");
+ REGEX_ASSERT(fields[4]=="");
+
+ delete pat1;
//
// RegexPattern::pattern()
{
UText re = UTEXT_INITIALIZER;
regextst_openUTF8FromInvariant(&re, "abc", -1, &status);
+ REGEX_VERBOSE_TEXT(&re);
RegexPattern *pat2;
pat2 = RegexPattern::compile(&re, flags, pe, status);
REGEX_CHECK_STATUS;
regextst_openUTF8FromInvariant(&input2, "not abc", -1, &status);
REGEX_VERBOSE_TEXT(&input2);
utext_openUChars(&empty, NULL, 0, &status);
-
+
int32_t input1Len = strlen("abcdef this is a test"); /* TODO: why not nativelen (input1) ? */
int32_t input2Len = strlen("not abc");
//
// Matcher creation and reset.
//
- RegexMatcher *m1 = pat2->matcher(&input1, RegexPattern::PATTERN_IS_UTEXT, status);
+ RegexMatcher *m1 = &pat2->matcher(status)->reset(&input1);
REGEX_CHECK_STATUS;
REGEX_ASSERT(m1->lookingAt(status) == TRUE);
const char str_abcdefthisisatest[] = { 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x74, 0x65, 0x73, 0x74, 0x00 }; /* abcdef this is a test */
delete m1;
delete pat2;
-
+
utext_close(&re);
utext_close(&input1);
utext_close(&input2);
UText re=UTEXT_INITIALIZER;
const char str_01234567_pat[] = { 0x30, 0x31, 0x28, 0x32, 0x33, 0x28, 0x34, 0x35, 0x29, 0x36, 0x37, 0x29, 0x28, 0x2e, 0x2a, 0x29, 0x00 }; /* 01(23(45)67)(.*) */
utext_openUTF8(&re, str_01234567_pat, -1, &status);
-
+
RegexPattern *pat = RegexPattern::compile(&re, flags, pe, status);
REGEX_CHECK_STATUS;
-
+
UText input = UTEXT_INITIALIZER;
const char str_0123456789[] = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x00 }; /* 0123456789 */
utext_openUTF8(&input, str_0123456789, -1, &status);
- RegexMatcher *matcher = pat->matcher(&input, RegexPattern::PATTERN_IS_UTEXT, status);
+ RegexMatcher *matcher = &pat->matcher(status)->reset(&input);
REGEX_CHECK_STATUS;
REGEX_ASSERT(matcher->lookingAt(status) == TRUE);
static const int32_t matchStarts[] = {0, 2, 4, 8};
REGEX_ASSERT_FAIL(matcher->start( 0, status), U_REGEX_INVALID_STATE);
matcher->lookingAt(status);
-
+
UnicodeString dest;
UText destText = UTEXT_INITIALIZER;
utext_openUnicodeString(&destText, &dest, &status);
UText *result;
//const char str_0123456789[] = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x00 }; /* 0123456789 */
- // Test shallow-clone API
+ // Test shallow-clone API
int64_t group_len;
result = matcher->group((UText *)NULL, group_len, status);
REGEX_CHECK_STATUS;
// destText is now immutable, reopen it
utext_close(&destText);
utext_openUnicodeString(&destText, &dest, &status);
-
- result = matcher->group(0, NULL, status);
+
+ int64_t length;
+ result = matcher->group(0, NULL, length, status);
REGEX_CHECK_STATUS;
REGEX_ASSERT_UTEXT_UTF8(str_0123456789, result);
utext_close(result);
- result = matcher->group(0, &destText, status);
+ result = matcher->group(0, &destText, length, status);
REGEX_CHECK_STATUS;
REGEX_ASSERT(result == &destText);
- REGEX_ASSERT_UTEXT_UTF8(str_0123456789, result);
-
- result = matcher->group(1, NULL, status);
+ REGEX_ASSERT(utext_getNativeIndex(result) == 0);
+ REGEX_ASSERT(length == 10);
+ REGEX_ASSERT_UTEXT_INVARIANT("0123456789", result);
+
+ // Capture Group 1 == "234567"
+ result = matcher->group(1, NULL, length, status);
REGEX_CHECK_STATUS;
- const char str_234567[] = { 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x00 }; /* 234567 */
- REGEX_ASSERT_UTEXT_UTF8(str_234567, result);
+ REGEX_ASSERT(utext_getNativeIndex(result) == 2);
+ REGEX_ASSERT(length == 6);
+ REGEX_ASSERT_UTEXT_INVARIANT("0123456789", result);
utext_close(result);
- result = matcher->group(1, &destText, status);
+
+ result = matcher->group(1, &destText, length, status);
REGEX_CHECK_STATUS;
REGEX_ASSERT(result == &destText);
- REGEX_ASSERT_UTEXT_UTF8(str_234567, result);
-
- result = matcher->group(2, NULL, status);
+ REGEX_ASSERT(utext_getNativeIndex(result) == 2);
+ REGEX_ASSERT(length == 6);
+ REGEX_ASSERT_UTEXT_INVARIANT("0123456789", result);
+ utext_close(result);
+
+ // Capture Group 2 == "45"
+ result = matcher->group(2, NULL, length, status);
REGEX_CHECK_STATUS;
- const char str_45[] = { 0x34, 0x35, 0x00 }; /* 45 */
- REGEX_ASSERT_UTEXT_UTF8(str_45, result);
+ REGEX_ASSERT(utext_getNativeIndex(result) == 4);
+ REGEX_ASSERT(length == 2);
+ REGEX_ASSERT_UTEXT_INVARIANT("0123456789", result);
utext_close(result);
- result = matcher->group(2, &destText, status);
+
+ result = matcher->group(2, &destText, length, status);
REGEX_CHECK_STATUS;
REGEX_ASSERT(result == &destText);
- REGEX_ASSERT_UTEXT_UTF8(str_45, result);
-
- result = matcher->group(3, NULL, status);
+ REGEX_ASSERT(utext_getNativeIndex(result) == 4);
+ REGEX_ASSERT(length == 2);
+ REGEX_ASSERT_UTEXT_INVARIANT("0123456789", result);
+ utext_close(result);
+
+ // Capture Group 3 == "89"
+ result = matcher->group(3, NULL, length, status);
REGEX_CHECK_STATUS;
- const char str_89[] = { 0x38, 0x39, 0x00 }; /* 89 */
- REGEX_ASSERT_UTEXT_UTF8(str_89, result);
+ REGEX_ASSERT(utext_getNativeIndex(result) == 8);
+ REGEX_ASSERT(length == 2);
+ REGEX_ASSERT_UTEXT_INVARIANT("0123456789", result);
utext_close(result);
- result = matcher->group(3, &destText, status);
+
+ result = matcher->group(3, &destText, length, status);
REGEX_CHECK_STATUS;
REGEX_ASSERT(result == &destText);
- REGEX_ASSERT_UTEXT_UTF8(str_89, result);
+ REGEX_ASSERT(utext_getNativeIndex(result) == 8);
+ REGEX_ASSERT(length == 2);
+ REGEX_ASSERT_UTEXT_INVARIANT("0123456789", result);
+ utext_close(result);
+ // Capture Group number out of range.
+ status = U_ZERO_ERROR;
REGEX_ASSERT_FAIL(matcher->group(-1, status), U_INDEX_OUTOFBOUNDS_ERROR);
+ status = U_ZERO_ERROR;
REGEX_ASSERT_FAIL(matcher->group( 4, status), U_INDEX_OUTOFBOUNDS_ERROR);
+ status = U_ZERO_ERROR;
matcher->reset();
REGEX_ASSERT_FAIL(matcher->group( 0, status), U_REGEX_INVALID_STATE);
delete matcher;
delete pat;
-
+
utext_close(&destText);
utext_close(&input);
utext_close(&re);
utext_openUTF8(&input, str_abcabcabc, -1, &status);
// 012345678901234567
- RegexMatcher *matcher = pat->matcher(&input, RegexPattern::PATTERN_IS_UTEXT, status);
+ RegexMatcher *matcher = &pat->matcher(status)->reset(&input);
REGEX_CHECK_STATUS;
REGEX_ASSERT(matcher->find());
REGEX_ASSERT(matcher->start(status) == 1);
delete matcher;
delete pat;
-
+
utext_close(&input);
utext_close(&re);
}
utext_openUTF8(&re, str_Gabcabc, -1, &status);
RegexPattern *pat = RegexPattern::compile(&re, flags, pe, status);
-
+
REGEX_CHECK_STATUS;
UText input = UTEXT_INITIALIZER;
const char str_abcabcabc[] = { 0x2e, 0x61, 0x62, 0x63, 0x61, 0x62, 0x63, 0x2e, 0x61, 0x62, 0x63, 0x2e, 0x2e, 0x00 }; /* .abcabc.abc.. */
utext_openUTF8(&input, str_abcabcabc, -1, &status);
// 012345678901234567
- RegexMatcher *matcher = pat->matcher(&input, RegexPattern::PATTERN_IS_UTEXT, status);
+ RegexMatcher *matcher = &pat->matcher(status)->reset(&input);
REGEX_CHECK_STATUS;
REGEX_ASSERT(matcher->find());
REGEX_ASSERT(matcher->start(status) == 0);
delete matcher;
delete pat;
-
+
utext_close(&input);
utext_close(&re);
}
REGEX_ASSERT(m.end(status) == i);
}
REGEX_ASSERT(i==20);
-
+
utext_close(&s);
}
{
REGEX_ASSERT(m.end(status) == (i<4 ? i+1 : i));
}
REGEX_ASSERT(i==5);
-
+
utext_close(&s);
}
delete m;
delete p;
}
-
+
//
// Regions
//
REGEX_VERBOSE_TEXT(&testPattern);
regextst_openUTF8FromInvariant(&testText, "This is test data", -1, &status);
REGEX_VERBOSE_TEXT(&testText);
-
+
RegexMatcher m(&testPattern, &testText, 0, status);
REGEX_CHECK_STATUS;
REGEX_ASSERT(m.regionStart() == 0);
REGEX_ASSERT(m.regionEnd() == (int32_t)strlen("This is test data"));
REGEX_ASSERT(m.hasTransparentBounds() == FALSE);
REGEX_ASSERT(m.hasAnchoringBounds() == TRUE);
-
+
m.region(2,4, status);
REGEX_CHECK_STATUS;
REGEX_ASSERT(m.matches(status));
REGEX_ASSERT(m.start(status)==2);
REGEX_ASSERT(m.end(status)==4);
REGEX_CHECK_STATUS;
-
+
m.reset();
REGEX_ASSERT(m.regionStart() == 0);
REGEX_ASSERT(m.regionEnd() == (int32_t)strlen("This is test data"));
-
+
regextst_openUTF8FromInvariant(&testText, "short", -1, &status);
REGEX_VERBOSE_TEXT(&testText);
m.reset(&testText);
REGEX_ASSERT(m.regionStart() == 0);
REGEX_ASSERT(m.regionEnd() == (int32_t)strlen("short"));
-
+
REGEX_ASSERT(m.hasAnchoringBounds() == TRUE);
REGEX_ASSERT(&m == &m.useAnchoringBounds(FALSE));
REGEX_ASSERT(m.hasAnchoringBounds() == FALSE);
REGEX_ASSERT(&m == &m.reset());
REGEX_ASSERT(m.hasAnchoringBounds() == FALSE);
-
+
REGEX_ASSERT(&m == &m.useAnchoringBounds(TRUE));
REGEX_ASSERT(m.hasAnchoringBounds() == TRUE);
REGEX_ASSERT(&m == &m.reset());
REGEX_ASSERT(m.hasAnchoringBounds() == TRUE);
-
+
REGEX_ASSERT(m.hasTransparentBounds() == FALSE);
REGEX_ASSERT(&m == &m.useTransparentBounds(TRUE));
REGEX_ASSERT(m.hasTransparentBounds() == TRUE);
REGEX_ASSERT(m.hasTransparentBounds() == FALSE);
REGEX_ASSERT(&m == &m.reset());
REGEX_ASSERT(m.hasTransparentBounds() == FALSE);
-
+
utext_close(&testText);
utext_close(&testPattern);
}
-
+
//
// hitEnd() and requireEnd()
//
const char str_aabb[] = { 0x61, 0x61, 0x62, 0x62, 0x00 }; /* aabb */
utext_openUTF8(&testPattern, str_, -1, &status);
utext_openUTF8(&testText, str_aabb, -1, &status);
-
+
RegexMatcher m1(&testPattern, &testText, 0, status);
REGEX_ASSERT(m1.lookingAt(status) == TRUE);
REGEX_ASSERT(m1.hitEnd() == TRUE);
REGEX_ASSERT(m1.requireEnd() == FALSE);
REGEX_CHECK_STATUS;
-
+
status = U_ZERO_ERROR;
const char str_a[] = { 0x61, 0x2a, 0x00 }; /* a* */
utext_openUTF8(&testPattern, str_a, -1, &status);
REGEX_ASSERT(m3.hitEnd() == TRUE);
REGEX_ASSERT(m3.requireEnd() == TRUE);
REGEX_CHECK_STATUS;
-
+
utext_close(&testText);
utext_close(&testPattern);
}
REGEX_VERBOSE_TEXT(&re);
RegexPattern *pat = RegexPattern::compile(&re, flags, pe, status);
REGEX_CHECK_STATUS;
-
+
char data[] = { 0x2e, 0x61, 0x62, 0x63, 0x2e, 0x2e, 0x61, 0x62, 0x63, 0x2e, 0x2e, 0x2e, 0x61, 0x62, 0x63, 0x2e, 0x2e, 0x00 }; /* .abc..abc...abc.. */
// 012345678901234567
UText dataText = UTEXT_INITIALIZER;
utext_openUTF8(&dataText, data, -1, &status);
REGEX_CHECK_STATUS;
REGEX_VERBOSE_TEXT(&dataText);
- RegexMatcher *matcher = pat->matcher(&dataText, RegexPattern::PATTERN_IS_UTEXT, status);
+ RegexMatcher *matcher = &pat->matcher(status)->reset(&dataText);
//
// Plain vanilla matches.
UText destText = UTEXT_INITIALIZER;
utext_openUnicodeString(&destText, &dest, &status);
UText *result;
-
+
UText replText = UTEXT_INITIALIZER;
-
+
const char str_yz[] = { 0x79, 0x7a, 0x00 }; /* yz */
utext_openUTF8(&replText, str_yz, -1, &status);
REGEX_VERBOSE_TEXT(&replText);
const char str_abxabxabx[] = { 0x2e, 0x61, 0x62, 0x78, 0x2e, 0x2e, 0x61, 0x62, 0x78, 0x2e, 0x2e, 0x2e, 0x61, 0x62, 0x78, 0x2e, 0x2e, 0x00 }; /* .abx..abx...abx.. */
utext_openUTF8(&dataText, str_abxabxabx, -1, &status);
matcher->reset(&dataText);
-
+
result = matcher->replaceFirst(&replText, NULL, status);
REGEX_CHECK_STATUS;
REGEX_ASSERT_UTEXT_UTF8(str_abxabxabx, result);
//
utext_openUTF8(&dataText, NULL, 0, &status);
matcher->reset(&dataText);
-
+
result = matcher->replaceFirst(&replText, NULL, status);
REGEX_CHECK_STATUS;
REGEX_ASSERT_UTEXT_UTF8("", result);
//
utext_openUTF8(&dataText, data, -1, &status); // ".abc..abc...abc.."
matcher->reset(&dataText);
-
+
utext_openUTF8(&replText, NULL, 0, &status);
result = matcher->replaceFirst(&replText, NULL, status);
REGEX_CHECK_STATUS;
const char str_abcdefg[] = { 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x00 }; /* abcdefg */
utext_openUTF8(&dataText, str_abcdefg, -1, &status);
- RegexMatcher *matcher2 = pat2->matcher(&dataText, RegexPattern::PATTERN_IS_UTEXT, status);
+ RegexMatcher *matcher2 = &pat2->matcher(status)->reset(&dataText);
REGEX_CHECK_STATUS;
-
+
const char str_11[] = { 0x24, 0x31, 0x24, 0x31, 0x00 }; /* $1$1 */
utext_openUTF8(&replText, str_11, -1, &status);
result = matcher2->replaceFirst(&replText, NULL, status);
REGEX_CHECK_STATUS;
REGEX_ASSERT(result == &destText);
REGEX_ASSERT_UTEXT_UTF8(str_bcbcdefg, result);
-
- regextst_openUTF8FromInvariant(&replText, "The value of \\$1 is $1.", -1, &status);
+
+ const char str_v[24] = { 0x54, 0x68, 0x65, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x5c, 0x24, 0x31, 0x20, 0x69, 0x73, 0x20, 0x24, 0x31, 0x2e, 0x00 }; /* The value of \$1 is $1. */
+ utext_openUTF8(&replText, str_v, -1, &status);
+ REGEX_VERBOSE_TEXT(&replText);
result = matcher2->replaceFirst(&replText, NULL, status);
REGEX_CHECK_STATUS;
const char str_Thevalueof1isbcdefg[] = { 0x54, 0x68, 0x65, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x24, 0x31, 0x20, 0x69, 0x73, 0x20, 0x62, 0x63, 0x2e, 0x64, 0x65, 0x66, 0x67, 0x00 }; /* The value of $1 is bc.defg */
REGEX_CHECK_STATUS;
REGEX_ASSERT(result == &destText);
REGEX_ASSERT_UTEXT_UTF8(str_Thevalueof1isbcdefg, result);
-
- const char str_byitselfnogroupnumber[] = { 0x24, 0x20, 0x62, 0x79, 0x20, 0x69, 0x74, 0x73, 0x65, 0x6c, 0x66, 0x2c, 0x20, 0x6e, 0x6f, 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x24, 0x24, 0x24, 0x00 }; /* $ by itself, no group number $$$ */
+
+ const char str_byitselfnogroupnumber[] = { 0x5c, 0x24, 0x20, 0x62, 0x79, 0x20, 0x69, 0x74, 0x73, 0x65, 0x6c,
+ 0x66, 0x2c, 0x20, 0x6e, 0x6f, 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x6e, 0x75, 0x6d, 0x62,
+ 0x65, 0x72, 0x20, 0x5c, 0x24, 0x5c, 0x24, 0x5c, 0x24, 0x00 }; /* \$ by itself, no group number \$\$\$ */
utext_openUTF8(&replText, str_byitselfnogroupnumber, -1, &status);
result = matcher2->replaceFirst(&replText, NULL, status);
REGEX_CHECK_STATUS;
supplDigitChars[24] = 0x9F;
supplDigitChars[25] = 0x8F;
utext_openUTF8(&replText, (char *)supplDigitChars, -1, &status);
-
+
result = matcher2->replaceFirst(&replText, NULL, status);
REGEX_CHECK_STATUS;
const char str_SupplementalDigit1bcdefg[] = { 0x53, 0x75, 0x70, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x20, 0x44, 0x69, 0x67, 0x69, 0x74, 0x20, 0x31, 0x20, 0x62, 0x63, 0x2e, 0x64, 0x65, 0x66, 0x67, 0x00 }; /* Supplemental Digit 1 bc.defg */
utext_openUTF8(&dataText, str_abc1abc2abc3, -1, &status);
utext_openUTF8(&replText, str_u0043, -1, &status);
matcher->reset(&dataText);
-
+
result = matcher->replaceAll(&replText, NULL, status);
REGEX_CHECK_STATUS;
const char str_C1C2C3[] = { 0x2d, 0x2d, 0x43, 0x2d, 0x2d, 0x20, 0x31, 0x20, 0x2d, 0x2d, 0x43, 0x2d, 0x2d, 0x20, 0x32, 0x20, 0x2d, 0x2d, 0x43, 0x2d, 0x2d, 0x20, 0x33, 0x00 }; /* --C-- 1 --C-- 2 --C-- 3 */
matcher->reset(&dataText);
unsigned char expected[] = { 0x2d, 0x2d, 0x78, 0x78, 0x78, 0x78, 0x2d, 0x2d, 0x20, 0x21, 0x00 }; /* --xxxx-- ! */ // \U00010000, "LINEAR B SYLLABLE B008 A"
- // 0123456789
+ // 0123456789
expected[2] = 0xF0;
expected[3] = 0x90;
expected[4] = 0x80;
utext_openUTF8(&re, str_ssee, -1, &status);
utext_openUTF8(&dataText, str_blah, -1, &status);
utext_openUTF8(&replText, str_ooh, -1, &status);
-
+
RegexMatcher m(&re, 0, status);
REGEX_CHECK_STATUS;
-
+
UnicodeString result;
UText resultText = UTEXT_INITIALIZER;
utext_openUnicodeString(&resultText, &result, &status);
m.appendTail(&resultText, status);
const char str_blah9[] = { 0x54, 0x68, 0x65, 0x20, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x73, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x65, 0x6e, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x65, 0x65, 0x20, 0x6f, 0x6f, 0x68, 0x20, 0x66, 0x69, 0x6e, 0x00 }; /* The matches start with ss and end with ee ooh fin */
REGEX_ASSERT_UTEXT_UTF8(str_blah9, &resultText);
-
+
utext_close(&resultText);
}
delete pat2;
delete matcher;
delete pat;
-
+
utext_close(&dataText);
utext_close(&replText);
utext_close(&destText);
UText re2 = UTEXT_INITIALIZER;
UErrorCode status = U_ZERO_ERROR;
UParseError pe;
-
+
const char str_abcalmz[] = { 0x61, 0x62, 0x63, 0x5b, 0x61, 0x2d, 0x6c, 0x5d, 0x5b, 0x6d, 0x2d, 0x7a, 0x5d, 0x00 }; /* abc[a-l][m-z] */
const char str_def[] = { 0x64, 0x65, 0x66, 0x00 }; /* def */
utext_openUTF8(&re1, str_abcalmz, -1, &status);
delete pat1a;
delete pat1;
delete pat2;
-
+
utext_close(&re1);
utext_close(&re2);
UText pattern = UTEXT_INITIALIZER;
const char str_pL[] = { 0x5c, 0x70, 0x7b, 0x4c, 0x7d, 0x2b, 0x00 }; /* \p{L}+ */
utext_openUTF8(&pattern, str_pL, -1, &status);
-
+
RegexPattern *pSource = RegexPattern::compile(&pattern, 0, status);
RegexPattern *pClone = pSource->clone();
delete pSource;
RegexMatcher *mFromClone = pClone->matcher(status);
REGEX_CHECK_STATUS;
-
+
UText input = UTEXT_INITIALIZER;
const char str_HelloWorld[] = { 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x00 }; /* Hello World */
utext_openUTF8(&input, str_HelloWorld, -1, &status);
REGEX_ASSERT(mFromClone->find() == FALSE);
delete mFromClone;
delete pClone;
-
+
utext_close(&input);
utext_close(&pattern);
}
UErrorCode status = U_ZERO_ERROR;
UText pattern = UTEXT_INITIALIZER;
UText input = UTEXT_INITIALIZER;
-
+
const char str_randominput[] = { 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x20, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x00 }; /* random input */
utext_openUTF8(&input, str_randominput, -1, &status);
utext_openUTF8(&pattern, str_dotstar, -1, &status);
REGEX_ASSERT(RegexPattern::matches(&pattern, &input, pe, status) == TRUE);
REGEX_CHECK_STATUS;
-
+
const char str_abc[] = { 0x61, 0x62, 0x63, 0x00 }; /* abc */
utext_openUTF8(&pattern, str_abc, -1, &status);
REGEX_ASSERT(RegexPattern::matches("abc", "random input", pe, status) == FALSE);
REGEX_CHECK_STATUS;
-
+
const char str_nput[] = { 0x2e, 0x2a, 0x6e, 0x70, 0x75, 0x74, 0x00 }; /* .*nput */
utext_openUTF8(&pattern, str_nput, -1, &status);
REGEX_ASSERT(RegexPattern::matches(".*nput", "random input", pe, status) == TRUE);
REGEX_CHECK_STATUS;
-
+
utext_openUTF8(&pattern, str_randominput, -1, &status);
REGEX_ASSERT(RegexPattern::matches("random input", "random input", pe, status) == TRUE);
REGEX_CHECK_STATUS;
utext_openUTF8(&pattern, str_u, -1, &status);
REGEX_ASSERT(RegexPattern::matches(".*u", "random input", pe, status) == FALSE);
REGEX_CHECK_STATUS;
-
+
utext_openUTF8(&input, str_abc, -1, &status);
utext_openUTF8(&pattern, str_abc, -1, &status);
status = U_INDEX_OUTOFBOUNDS_ERROR;
REGEX_ASSERT(RegexPattern::matches("abc", "abc", pe, status) == FALSE);
REGEX_ASSERT(status == U_INDEX_OUTOFBOUNDS_ERROR);
-
+
utext_close(&input);
utext_close(&pattern);
}
n = pat1->split(" Now is the time ", fields, 10, status);
REGEX_CHECK_STATUS;
- REGEX_ASSERT(n==5);
+ REGEX_ASSERT(n==6);
REGEX_ASSERT(fields[0]=="");
REGEX_ASSERT(fields[1]=="Now");
REGEX_ASSERT(fields[2]=="is");
REGEX_ASSERT(fields[3]=="the");
REGEX_ASSERT(fields[4]=="time");
REGEX_ASSERT(fields[5]=="");
+ REGEX_ASSERT(fields[6]=="");
+ fields[2] = "*";
n = pat1->split(" ", fields, 10, status);
REGEX_CHECK_STATUS;
- REGEX_ASSERT(n==1);
+ REGEX_ASSERT(n==2);
REGEX_ASSERT(fields[0]=="");
+ REGEX_ASSERT(fields[1]=="");
+ REGEX_ASSERT(fields[2]=="*");
fields[0] = "foo";
n = pat1->split("", fields, 10, status);
REGEX_CHECK_STATUS;
status = U_ZERO_ERROR;
+ fields[6] = fields[7] = "*";
n = pat1->split("<a>Now is <b>the time<c>", fields, 10, status);
REGEX_CHECK_STATUS;
- REGEX_ASSERT(n==6);
+ REGEX_ASSERT(n==7);
REGEX_ASSERT(fields[0]=="");
REGEX_ASSERT(fields[1]=="a");
REGEX_ASSERT(fields[2]=="Now is ");
REGEX_ASSERT(fields[4]=="the time");
REGEX_ASSERT(fields[5]=="c");
REGEX_ASSERT(fields[6]=="");
+ REGEX_ASSERT(fields[7]=="*");
REGEX_ASSERT(status==U_ZERO_ERROR);
+ fields[6] = fields[7] = "*";
n = pat1->split(" <a>Now is <b>the time<c>", fields, 10, status);
REGEX_CHECK_STATUS;
- REGEX_ASSERT(n==6);
+ REGEX_ASSERT(n==7);
REGEX_ASSERT(fields[0]==" ");
REGEX_ASSERT(fields[1]=="a");
REGEX_ASSERT(fields[2]=="Now is ");
REGEX_ASSERT(fields[4]=="the time");
REGEX_ASSERT(fields[5]=="c");
REGEX_ASSERT(fields[6]=="");
+ REGEX_ASSERT(fields[7]=="*");
status = U_ZERO_ERROR;
fields[6] = "foo";
- n = pat1->split(" <a>Now is <b>the time<c>", fields, 6, status);
+ n = pat1->split(" <a>Now is <b>the time<c> ", fields, 6, status);
REGEX_CHECK_STATUS;
REGEX_ASSERT(n==6);
REGEX_ASSERT(fields[0]==" ");
REGEX_ASSERT(fields[2]=="Now is ");
REGEX_ASSERT(fields[3]=="b");
REGEX_ASSERT(fields[4]=="the time");
- REGEX_ASSERT(fields[5]=="c");
+ REGEX_ASSERT(fields[5]==" ");
REGEX_ASSERT(fields[6]=="foo");
status = U_ZERO_ERROR;
delete pat1;
+ //
+ // split of a UText based string, with library allocating output UTexts.
+ //
+ {
+ status = U_ZERO_ERROR;
+ RegexMatcher matcher(UnicodeString("(:)"), 0, status);
+ UnicodeString stringToSplit("first:second:third");
+ UText *textToSplit = utext_openUnicodeString(NULL, &stringToSplit, &status);
+ REGEX_CHECK_STATUS;
+
+ UText *splits[10] = {NULL};
+ int32_t numFields = matcher.split(textToSplit, splits, UPRV_LENGTHOF(splits), status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(numFields == 5);
+ REGEX_ASSERT_UTEXT_INVARIANT("first", splits[0]);
+ REGEX_ASSERT_UTEXT_INVARIANT(":", splits[1]);
+ REGEX_ASSERT_UTEXT_INVARIANT("second", splits[2]);
+ REGEX_ASSERT_UTEXT_INVARIANT(":", splits[3]);
+ REGEX_ASSERT_UTEXT_INVARIANT("third", splits[4]);
+ REGEX_ASSERT(splits[5] == NULL);
+
+ for (int i=0; i<UPRV_LENGTHOF(splits); i++) {
+ if (splits[i]) {
+ utext_close(splits[i]);
+ splits[i] = NULL;
+ }
+ }
+ utext_close(textToSplit);
+ }
+
+
//
// RegexPattern::pattern() and patternText()
//
REGEX_ASSERT(pat1->pattern() == "");
REGEX_ASSERT_UTEXT_UTF8("", pat1->patternText(status));
delete pat1;
-
- regextst_openUTF8FromInvariant(&re1, "(Hello, world)*", -1, &status);
+ const char *helloWorldInvariant = "(Hello, world)*";
+ regextst_openUTF8FromInvariant(&re1, helloWorldInvariant, -1, &status);
pat1 = RegexPattern::compile(&re1, pe, status);
REGEX_CHECK_STATUS;
- REGEX_ASSERT(pat1->pattern() == "(Hello, world)*");
+ REGEX_ASSERT_UNISTR("(Hello, world)*", pat1->pattern());
REGEX_ASSERT_UTEXT_INVARIANT("(Hello, world)*", pat1->patternText(status));
delete pat1;
RegexMatcher quotedStuffMat(UNICODE_STRING_SIMPLE("\\s*([\\'\\\"/])(.*?)\\1"), 0, status);
RegexMatcher commentMat (UNICODE_STRING_SIMPLE("\\s*(#.*)?$"), 0, status);
- RegexMatcher flagsMat (UNICODE_STRING_SIMPLE("\\s*([ixsmdteDEGLMvabtyYzZ2-9]*)([:letter:]*)"), 0, status);
+ RegexMatcher flagsMat (UNICODE_STRING_SIMPLE("\\s*([ixsmdteDEGLMQvabtyYzZ2-9]*)([:letter:]*)"), 0, status);
RegexMatcher lineMat(UNICODE_STRING_SIMPLE("(.*?)\\r?\\n"), testString, 0, status);
UnicodeString testPattern; // The pattern for test from the test file.
UnicodeString matchString; // The marked up string to be used as input
if (U_FAILURE(status)){
- dataerrln("Construct RegexMatcher() error.");
+ dataerrln("Construct RegexMatcher() error - %s", u_errorName(status));
delete [] testData;
return;
}
break;
}
}
- nativeIndex = UTEXT_GETNATIVEINDEX(utext);
+ nativeIndex = (int32_t)UTEXT_GETNATIVEINDEX(utext);
return couldFind;
}
int32_t line) {
UnicodeString unEscapedInput;
UnicodeString deTaggedInput;
-
+
int32_t patternUTF8Length, inputUTF8Length;
char *patternChars = NULL, *inputChars = NULL;
UText patternText = UTEXT_INITIALIZER;
int32_t regionEnd = -1;
int32_t regionStartUTF8 = -1;
int32_t regionEndUTF8 = -1;
-
+
//
// Compile the caller's pattern
if (flags.indexOf((UChar)0x6d) >= 0) { // 'm' flag
bflags |= UREGEX_MULTILINE;
}
-
+
if (flags.indexOf((UChar)0x65) >= 0) { // 'e' flag
bflags |= UREGEX_ERROR_ON_UNKNOWN_ESCAPES;
}
if (flags.indexOf((UChar)0x44) >= 0) { // 'D' flag
bflags |= UREGEX_UNIX_LINES;
}
+ if (flags.indexOf((UChar)0x51) >= 0) { // 'Q' flag
+ bflags |= UREGEX_LITERAL;
+ }
callerPattern = RegexPattern::compile(pattern, bflags, pe, status);
goto cleanupAndReturn;
} else {
// Unexpected pattern compilation error.
- errln("Line %d: error %s compiling pattern.", line, u_errorName(status));
+ dataerrln("Line %d: error %s compiling pattern.", line, u_errorName(status));
goto cleanupAndReturn;
}
}
UTF8Converter = ucnv_open("UTF8", &status);
ucnv_setFromUCallBack(UTF8Converter, UCNV_FROM_U_CALLBACK_STOP, NULL, NULL, NULL, &status);
-
+
patternUTF8Length = pattern.extract(NULL, 0, UTF8Converter, status);
status = U_ZERO_ERROR; // buffer overflow
patternChars = new char[patternUTF8Length+1];
pattern.extract(patternChars, patternUTF8Length+1, UTF8Converter, status);
utext_openUTF8(&patternText, patternChars, patternUTF8Length, &status);
-
+
if (status == U_ZERO_ERROR) {
UTF8Pattern = RegexPattern::compile(&patternText, bflags, pe, status);
-
+
if (status != U_ZERO_ERROR) {
#if UCONFIG_NO_BREAK_ITERATION==1
// 'v' test flag means that the test pattern should not compile if ICU was configured
}
}
}
-
+
if (UTF8Pattern == NULL) {
// UTF-8 does not allow unpaired surrogates, so this could actually happen without being a failure of the engine
logln("Unable to create UTF-8 pattern, skipping UTF-8 tests for %s:%d", srcPath, line);
}
if (flags.indexOf((UChar)0x64) >= 0) { // 'd' flag
- RegexPatternDump(callerPattern);
+ callerPattern->dumpPattern();
}
if (flags.indexOf((UChar)0x45) >= 0) { // 'E' flag
numFinds = i;
}
}
-
+
// 'M' flag. Use matches() instead of find()
if (flags.indexOf((UChar)0x4d) >= 0) {
useMatchesFunc = TRUE;
if (flags.indexOf((UChar)0x74) >= 0) { // 't' trace flag
matcher->setTrace(TRUE);
}
-
+
if (UTF8Pattern != NULL) {
inputUTF8Length = deTaggedInput.extract(NULL, 0, UTF8Converter, status);
status = U_ZERO_ERROR; // buffer overflow
utext_openUTF8(&inputText, inputChars, inputUTF8Length, &status);
if (status == U_ZERO_ERROR) {
- UTF8Matcher = UTF8Pattern->matcher(&inputText, RegexPattern::PATTERN_IS_UTEXT, status);
+ UTF8Matcher = &UTF8Pattern->matcher(status)->reset(&inputText);
REGEX_CHECK_STATUS_L(line);
}
-
+
if (UTF8Matcher == NULL) {
// UTF-8 does not allow unpaired surrogates, so this could actually happen without being a failure of the engine
logln("Unable to create UTF-8 matcher, skipping UTF-8 tests for %s:%d", srcPath, line);
if (UTF8Matcher != NULL) {
if (regionStart>=0) (void) utextOffsetToNative(&inputText, regionStart, regionStartUTF8);
if (regionEnd>=0) (void) utextOffsetToNative(&inputText, regionEnd, regionEndUTF8);
-
+
// Fill out the native index UVector info.
// Only need 1 loop, from above we know groupStarts.size() = groupEnds.size()
for (i=0; i<groupStarts.size(); i++) {
}
setInt(groupStartsUTF8, startUTF8, i);
}
-
+
int32_t end = groupEnds.elementAti(i);
// -1 means there was no UVector slot and we won't be requesting that capture group for this test, don't bother inserting
if (end >= 0) {
UTF8Matcher->useTransparentBounds(TRUE);
}
}
-
-
+
+
//
// Do a find on the de-tagged input using the caller's pattern
}
}
matcher->setTrace(FALSE);
+ if (U_FAILURE(status)) {
+ errln("Error at line %d. ICU ErrorCode is %s", u_errorName(status));
+ }
//
// Match up the groups from the find() with the groups from the tags
// G option in test means that capture group data is not available in the
// expected results, so the check needs to be suppressed.
if (isMatch == FALSE && groupStarts.size() != 0) {
- errln("Error at line %d: Match expected, but none found.", line);
+ dataerrln("Error at line %d: Match expected, but none found.", line);
failed = TRUE;
goto cleanupAndReturn;
} else if (UTF8Matcher != NULL && isUTF8Match == FALSE && groupStarts.size() != 0) {
failed = TRUE;
goto cleanupAndReturn; // Good chance of subsequent bogus errors. Stop now.
}
-
+
int32_t expectedEnd = (i >= groupEnds.size()? -1 : groupEnds.elementAti(i));
int32_t expectedEndUTF8 = (i >= groupEndsUTF8.size()? -1 : groupEndsUTF8.elementAti(i));
if (matcher->end(i, status) != expectedEnd) {
errln("Error at line %d: requireEnd() returned TRUE. Expected FALSE (UTF8)", line);
failed = TRUE;
}
-
+
if ((flags.indexOf((UChar)0x79) >= 0) && // 'y' flag: RequireEnd() == true
matcher->requireEnd() == FALSE) {
errln("Error at line %d: requireEnd() returned FALSE. Expected TRUE", line);
errln("Error at line %d: requireEnd() returned FALSE. Expected TRUE (UTF8)", line);
failed = TRUE;
}
-
+
if ((flags.indexOf((UChar)0x5A) >= 0) && // 'Z' flag: hitEnd() == false
matcher->hitEnd() == TRUE) {
errln("Error at line %d: hitEnd() returned TRUE. Expected FALSE", line);
errln("Error at line %d: hitEnd() returned TRUE. Expected FALSE (UTF8)", line);
failed = TRUE;
}
-
+
if ((flags.indexOf((UChar)0x7A) >= 0) && // 'z' flag: hitEnd() == true
matcher->hitEnd() == FALSE) {
errln("Error at line %d: hitEnd() returned FALSE. Expected TRUE", line);
delete UTF8Pattern;
delete matcher;
delete callerPattern;
-
+
utext_close(&inputText);
delete[] inputChars;
utext_close(&patternText);
REGEX_ERR("abc{1,,2}",1,7, U_REGEX_BAD_INTERVAL);
REGEX_ERR("abc{1,2a}",1,8, U_REGEX_BAD_INTERVAL);
REGEX_ERR("abc{222222222222222222222}",1,14, U_REGEX_NUMBER_TOO_BIG);
- REGEX_ERR("abc{5,50000000000}", 1, 17, U_REGEX_NUMBER_TOO_BIG); // Overflows int during scan
+ REGEX_ERR("abc{5,50000000000}", 1, 16, U_REGEX_NUMBER_TOO_BIG); // Overflows int during scan
REGEX_ERR("abc{5,687865858}", 1, 16, U_REGEX_NUMBER_TOO_BIG); // Overflows regex binary format
REGEX_ERR("abc{687865858,687865859}", 1, 24, U_REGEX_NUMBER_TOO_BIG);
//-------------------------------------------------------------------------------
-//
+//
// Read a text data file, convert it to UChars, and return the data
// in one big UChar * buffer, which the caller must delete.
//
ucnv_close(conv);
if (U_FAILURE(status)) {
errln("ucnv_toUChars: ICU Error \"%s\"\n", u_errorName(status));
- delete retPtr;
+ delete []retPtr;
retPtr = 0;
ulen = 0;
};
lineNum, expected?"":"no ", found?"":"no " );
continue;
}
-
+
// Don't try to check expected results if there is no match.
// (Some have stuff in the expected fields)
if (!found) {
if (flagStr.indexOf(UChar_x) != -1) {
flags |= UREGEX_COMMENTS;
}
-
+
//
// Put the pattern in a UTF-8 UText
//
//
// Run the test, check for expected match/don't match result.
//
- RegexMatcher *testMat = testPat->matcher(&inputText, RegexPattern::PATTERN_IS_UTEXT, status);
+ RegexMatcher *testMat = &testPat->matcher(status)->reset(&inputText);
UBool found = testMat->find();
UBool expected = FALSE;
if (fields[2].indexOf(UChar_y) >=0) {
lineNum, expected?"":"no ", found?"":"no " );
continue;
}
-
+
// Don't try to check expected results if there is no match.
// (Some have stuff in the expected fields)
if (!found) {
delete fieldPat;
delete [] testData;
-
+
utext_close(&patternText);
utext_close(&inputText);
-
+
delete [] patternChars;
delete [] inputChars;
//
// Bug6149 Verify limits to heap expansion for backtrack stack.
// Use this pattern,
-// "(a?){1,}"
-// The zero-length match will repeat forever.
-// (That this goes into a loop is another bug)
+// "(a?){1,8000000}"
+// Note: was an unbounded upperbounds, but that now has loop-breaking enabled.
+// This test is likely to be fragile, as further optimizations stop
+// more cases of pointless looping in the match engine.
//
//---------------------------------------------------------------
void RegexTest::Bug6149() {
- UnicodeString pattern("(a?){1,}");
+ UnicodeString pattern("(a?){1,8000000}");
UnicodeString s("xyz");
uint32_t flags = 0;
UErrorCode status = U_ZERO_ERROR;
void RegexTest::Callbacks() {
{
// Getter returns NULLs if no callback has been set
-
+
// The variables that the getter will fill in.
// Init to non-null values so that the action of the getter can be seen.
const void *returnedContext = &returnedContext;
URegexMatchCallback *returnedFn = &testCallBackFn;
-
+
UErrorCode status = U_ZERO_ERROR;
RegexMatcher matcher("x", 0, status);
REGEX_CHECK_STATUS;
REGEX_ASSERT(returnedFn == NULL);
REGEX_ASSERT(returnedContext == NULL);
}
-
+
{
// Set and Get work
callBackContext cbInfo = {this, 0, 0, 0};
REGEX_CHECK_STATUS;
REGEX_ASSERT(returnedFn == testCallBackFn);
REGEX_ASSERT(returnedContext == &cbInfo);
-
+
// A short-running match shouldn't invoke the callback
status = U_ZERO_ERROR;
cbInfo.reset(1);
REGEX_ASSERT(matcher.matches(status));
REGEX_CHECK_STATUS;
REGEX_ASSERT(cbInfo.numCalls == 0);
-
+
// A medium-length match that runs long enough to invoke the
// callback, but not so long that the callback aborts it.
status = U_ZERO_ERROR;
REGEX_ASSERT(matcher.matches(status)==FALSE);
REGEX_CHECK_STATUS;
REGEX_ASSERT(cbInfo.numCalls > 0);
-
+
// A longer running match that the callback function will abort.
status = U_ZERO_ERROR;
cbInfo.reset(4);
REGEX_ASSERT(matcher.matches(status)==FALSE);
REGEX_ASSERT(status == U_REGEX_STOPPED_BY_CALLER);
REGEX_ASSERT(cbInfo.numCalls == 4);
+
+ // A longer running find that the callback function will abort.
+ status = U_ZERO_ERROR;
+ cbInfo.reset(4);
+ s = "aaaaaaaaaaaaaaaaaaaaaaab";
+ matcher.reset(s);
+ REGEX_ASSERT(matcher.find(status)==FALSE);
+ REGEX_ASSERT(status == U_REGEX_STOPPED_BY_CALLER);
+ REGEX_ASSERT(cbInfo.numCalls == 4);
}
-
+
}
void reset(int32_t max) {maxCalls=max; numCalls=0;lastIndex=0;};
};
+// call-back function for find().
+// Return TRUE to continue the find().
+// Return FALSE to stop the find().
U_CDECL_BEGIN
static UBool U_CALLCONV
testProgressCallBackFn(const void *context, int64_t matchIndex) {
void RegexTest::FindProgressCallbacks() {
{
// Getter returns NULLs if no callback has been set
-
+
// The variables that the getter will fill in.
// Init to non-null values so that the action of the getter can be seen.
const void *returnedContext = &returnedContext;
URegexFindProgressCallback *returnedFn = &testProgressCallBackFn;
-
+
UErrorCode status = U_ZERO_ERROR;
RegexMatcher matcher("x", 0, status);
REGEX_CHECK_STATUS;
REGEX_ASSERT(returnedFn == NULL);
REGEX_ASSERT(returnedContext == NULL);
}
-
+
{
// Set and Get work
progressCallBackContext cbInfo = {this, 0, 0, 0};
const void *returnedContext;
URegexFindProgressCallback *returnedFn;
UErrorCode status = U_ZERO_ERROR;
- RegexMatcher matcher(UNICODE_STRING_SIMPLE("((.)+\\2)+x"), 0, status); // A pattern that can run long.
+ RegexMatcher matcher(UNICODE_STRING_SIMPLE("((.)\\2)x"), 0, status);
REGEX_CHECK_STATUS;
matcher.setFindProgressCallback(testProgressCallBackFn, &cbInfo, status);
REGEX_CHECK_STATUS;
REGEX_CHECK_STATUS;
REGEX_ASSERT(returnedFn == testProgressCallBackFn);
REGEX_ASSERT(returnedContext == &cbInfo);
-
- // A short-running match should NOT invoke the callback.
+
+ // A find that matches on the initial position does NOT invoke the callback.
status = U_ZERO_ERROR;
cbInfo.reset(100);
- UnicodeString s = "abxxx";
+ UnicodeString s = "aaxxx";
matcher.reset(s);
#if 0
matcher.setTrace(TRUE);
REGEX_ASSERT(matcher.find(0, status));
REGEX_CHECK_STATUS;
REGEX_ASSERT(cbInfo.numCalls == 0);
-
- // A medium running match that causes matcher.find() to invoke our callback for each index.
+
+ // A medium running find() that causes matcher.find() to invoke our callback for each index,
+ // but not so many times that we interrupt the operation.
status = U_ZERO_ERROR;
s = "aaaaaaaaaaaaaaaaaaab";
cbInfo.reset(s.length()); // Some upper limit for number of calls that is greater than size of our input string
REGEX_ASSERT(matcher.find(0, status)==FALSE);
REGEX_CHECK_STATUS;
REGEX_ASSERT(cbInfo.numCalls > 0 && cbInfo.numCalls < 25);
-
+
// A longer running match that causes matcher.find() to invoke our callback which we cancel/interrupt at some point.
status = U_ZERO_ERROR;
UnicodeString s1 = "aaaaaaaaaaaaaaaaaaaaaaab";
cbInfo.reset(s1.length() - 5); // Bail early somewhere near the end of input string
matcher.reset(s1);
REGEX_ASSERT(matcher.find(0, status)==FALSE);
- REGEX_CHECK_STATUS;
+ REGEX_ASSERT(status == U_REGEX_STOPPED_BY_CALLER);
REGEX_ASSERT(cbInfo.numCalls == s1.length() - 5);
-#if 0
// Now a match that will succeed, but after an interruption
status = U_ZERO_ERROR;
UnicodeString s2 = "aaaaaaaaaaaaaa aaaaaaaaab xxx";
cbInfo.reset(s2.length() - 10); // Bail early somewhere near the end of input string
matcher.reset(s2);
REGEX_ASSERT(matcher.find(0, status)==FALSE);
- REGEX_CHECK_STATUS;
+ REGEX_ASSERT(status == U_REGEX_STOPPED_BY_CALLER);
// Now retry the match from where left off
cbInfo.maxCalls = 100; // No callback limit
+ status = U_ZERO_ERROR;
REGEX_ASSERT(matcher.find(cbInfo.lastIndex, status));
REGEX_CHECK_STATUS;
-#endif
}
-
+
}
UText patternText = UTEXT_INITIALIZER;
UnicodeString buffer;
UText bufferText = UTEXT_INITIALIZER;
-
+
utext_openUnicodeString(&bufferText, &buffer, &status);
/*
regextst_openUTF8FromInvariant(&text2, "abcccxd", -1, &status);
u_uastrncpy(text2Chars, "abcccxd", sizeof(text2)/2);
utext_openUChars(&text2, text2Chars, -1, &status);
-
+
regextst_openUTF8FromInvariant(&patternText, "abc*d", -1, &status);
re = uregex_openUText(&patternText, 0, NULL, &status);
REGEX_ASSERT(resultText == &bufferText);
utext_setNativeIndex(resultText, 0);
utext_setNativeIndex(&text1, 0);
- REGEX_ASSERT(utext_compare(resultText, -1, &text1, -1) == 0);
-
+ REGEX_ASSERT(testUTextEqual(resultText, &text1));
+
resultText = uregex_getUText(re, &bufferText, &status);
REGEX_CHECK_STATUS;
REGEX_ASSERT(resultText == &bufferText);
utext_setNativeIndex(resultText, 0);
utext_setNativeIndex(&text1, 0);
- REGEX_ASSERT(utext_compare(resultText, -1, &text1, -1) == 0);
+ REGEX_ASSERT(testUTextEqual(resultText, &text1));
/* Then set a UChar * */
uregex_setText(re, text2Chars, 7, &status);
REGEX_ASSERT(resultText == &bufferText);
utext_setNativeIndex(resultText, 0);
utext_setNativeIndex(&text2, 0);
- REGEX_ASSERT(utext_compare(resultText, -1, &text2, -1) == 0);
-
+ REGEX_ASSERT(testUTextEqual(resultText, &text2));
+
uregex_close(re);
utext_close(&text1);
utext_close(&text2);
UChar text1[80];
UText *actual;
UBool result;
- u_uastrncpy(text1, "noise abc interior def, and this is off the end", sizeof(text1)/2);
+ int64_t length = 0;
+
+ u_uastrncpy(text1, "noise abc interior def, and this is off the end", UPRV_LENGTHOF(text1));
+ // 012345678901234567890123456789012345678901234567
+ // 0 1 2 3 4
status = U_ZERO_ERROR;
re = uregex_openC("abc(.*?)def", 0, NULL, &status);
result = uregex_find(re, 0, &status);
REGEX_ASSERT(result==TRUE);
- /* Capture Group 0, the full match. Should succeed. */
+ /* Capture Group 0, the full match. Should succeed. "abc interior def" */
status = U_ZERO_ERROR;
- actual = uregex_groupUTextDeep(re, 0, &bufferText, &status);
+ actual = uregex_groupUText(re, 0, &bufferText, &length, &status);
REGEX_CHECK_STATUS;
REGEX_ASSERT(actual == &bufferText);
- REGEX_ASSERT_UTEXT_INVARIANT("abc interior def", actual);
+ REGEX_ASSERT(utext_getNativeIndex(actual) == 6);
+ REGEX_ASSERT(length == 16);
+ REGEX_ASSERT(utext_nativeLength(actual) == 47);
- /* Capture group #1. Should succeed. */
+ /* Capture group #1. Should succeed, matching " interior ". */
status = U_ZERO_ERROR;
- actual = uregex_groupUTextDeep(re, 1, &bufferText, &status);
+ actual = uregex_groupUText(re, 1, &bufferText, &length, &status);
REGEX_CHECK_STATUS;
REGEX_ASSERT(actual == &bufferText);
- REGEX_ASSERT_UTEXT_INVARIANT(" interior ", actual);
+ REGEX_ASSERT(utext_getNativeIndex(actual) == 9); // position of " interior "
+ REGEX_ASSERT(length == 10);
+ REGEX_ASSERT(utext_nativeLength(actual) == 47);
/* Capture group out of range. Error. */
status = U_ZERO_ERROR;
- actual = uregex_groupUTextDeep(re, 2, &bufferText, &status);
+ actual = uregex_groupUText(re, 2, &bufferText, &length, &status);
REGEX_ASSERT(status == U_INDEX_OUTOFBOUNDS_ERROR);
REGEX_ASSERT(actual == &bufferText);
-
uregex_close(re);
}
-
+
/*
* replaceFirst()
*/
UChar text2[80];
UText replText = UTEXT_INITIALIZER;
UText *result;
-
status = U_ZERO_ERROR;
- u_uastrncpy(text1, "Replace xaax x1x x...x.", sizeof(text1)/2);
- u_uastrncpy(text2, "No match here.", sizeof(text2)/2);
+ utext_openUnicodeString(&bufferText, &buffer, &status);
+
+ status = U_ZERO_ERROR;
+ u_uastrncpy(text1, "Replace xaax x1x x...x.", UPRV_LENGTHOF(text1));
+ u_uastrncpy(text2, "No match here.", UPRV_LENGTHOF(text2)/2);
regextst_openUTF8FromInvariant(&replText, "<$1>", -1, &status);
re = uregex_openC("x(.*?)x", 0, NULL, &status);
/* Normal case, with match */
uregex_setText(re, text1, -1, &status);
+ REGEX_CHECK_STATUS;
utext_replace(&bufferText, 0, utext_nativeLength(&bufferText), NULL, 0, &status);
+ REGEX_CHECK_STATUS;
result = uregex_replaceFirstUText(re, &replText, &bufferText, &status);
REGEX_CHECK_STATUS;
REGEX_ASSERT(result == &bufferText);
REGEX_CHECK_STATUS;
REGEX_ASSERT(result == &bufferText);
REGEX_ASSERT_UTEXT_INVARIANT("No match here.", result);
-
+
/* Unicode escapes */
uregex_setText(re, text1, -1, &status);
- regextst_openUTF8FromInvariant(&replText, "\\\\\\u0041$1\\U00000042$\\a", -1, &status);
+ regextst_openUTF8FromInvariant(&replText, "\\\\\\u0041$1\\U00000042\\$\\a", -1, &status);
utext_replace(&bufferText, 0, utext_nativeLength(&bufferText), NULL, 0, &status);
result = uregex_replaceFirstUText(re, &replText, &bufferText, &status);
REGEX_CHECK_STATUS;
* splitUText() uses the C++ API directly, and the UnicodeString version uses mutable UTexts,
* so we don't need to test it here.
*/
-
+
utext_close(&bufferText);
utext_close(&patternText);
}
+
+//--------------------------------------------------------------
+//
+// NamedCapture Check basic named capture group functionality
+//
+//--------------------------------------------------------------
+void RegexTest::NamedCapture() {
+ UErrorCode status = U_ZERO_ERROR;
+ RegexPattern *pat = RegexPattern::compile(UnicodeString(
+ "abc()()(?<three>xyz)(de)(?<five>hmm)(?<six>oh)f\\k<five>"), 0, status);
+ REGEX_CHECK_STATUS;
+ int32_t group = pat->groupNumberFromName("five", -1, status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(5 == group);
+ group = pat->groupNumberFromName("three", -1, status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(3 == group);
+
+ status = U_ZERO_ERROR;
+ group = pat->groupNumberFromName(UnicodeString("six"), status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(6 == group);
+
+ status = U_ZERO_ERROR;
+ group = pat->groupNumberFromName(UnicodeString("nosuch"), status);
+ U_ASSERT(status == U_REGEX_INVALID_CAPTURE_GROUP_NAME);
+
+ status = U_ZERO_ERROR;
+
+ // After copying a pattern, named capture should still work in the copy.
+ RegexPattern *copiedPat = new RegexPattern(*pat);
+ REGEX_ASSERT(*copiedPat == *pat);
+ delete pat; pat = NULL; // Delete original, copy should have no references back to it.
+
+ group = copiedPat->groupNumberFromName("five", -1, status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(5 == group);
+ group = copiedPat->groupNumberFromName("three", -1, status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(3 == group);
+ delete copiedPat;
+
+ // ReplaceAll with named capture group.
+ status = U_ZERO_ERROR;
+ UnicodeString text("Substitution of <<quotes>> for <<double brackets>>");
+ RegexMatcher *m = new RegexMatcher(UnicodeString("<<(?<mid>.+?)>>"), text, 0, status);
+ REGEX_CHECK_STATUS;
+ // m.pattern().dumpPattern();
+ UnicodeString replacedText = m->replaceAll("'${mid}'", status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(UnicodeString("Substitution of 'quotes' for 'double brackets'") == replacedText);
+ delete m;
+
+ // ReplaceAll, allowed capture group numbers.
+ text = UnicodeString("abcmxyz");
+ m = new RegexMatcher(UnicodeString("..(?<one>m)(.)(.)"), text, 0, status);
+ REGEX_CHECK_STATUS;
+
+ status = U_ZERO_ERROR;
+ replacedText = m->replaceAll(UnicodeString("<$0>"), status); // group 0, full match, is allowed.
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(UnicodeString("a<bcmxy>z") == replacedText);
+
+ status = U_ZERO_ERROR;
+ replacedText = m->replaceAll(UnicodeString("<$1>"), status); // group 1 by number.
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(UnicodeString("a<m>z") == replacedText);
+
+ status = U_ZERO_ERROR;
+ replacedText = m->replaceAll(UnicodeString("<${one}>"), status); // group 1 by name.
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(UnicodeString("a<m>z") == replacedText);
+
+ status = U_ZERO_ERROR;
+ replacedText = m->replaceAll(UnicodeString("<$2>"), status); // group 2.
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(UnicodeString("a<x>z") == replacedText);
+
+ status = U_ZERO_ERROR;
+ replacedText = m->replaceAll(UnicodeString("<$3>"), status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(UnicodeString("a<y>z") == replacedText);
+
+ status = U_ZERO_ERROR;
+ replacedText = m->replaceAll(UnicodeString("<$4>"), status);
+ REGEX_ASSERT(status == U_INDEX_OUTOFBOUNDS_ERROR);
+
+ status = U_ZERO_ERROR;
+ replacedText = m->replaceAll(UnicodeString("<$04>"), status); // group 0, leading 0,
+ REGEX_CHECK_STATUS; // trailing out-of-range 4 passes through.
+ REGEX_ASSERT(UnicodeString("a<bcmxy4>z") == replacedText);
+
+ status = U_ZERO_ERROR;
+ replacedText = m->replaceAll(UnicodeString("<$000016>"), status); // Consume leading zeroes. Don't consume digits
+ REGEX_CHECK_STATUS; // that push group num out of range.
+ REGEX_ASSERT(UnicodeString("a<m6>z") == replacedText); // This is group 1.
+
+ status = U_ZERO_ERROR;
+ replacedText = m->replaceAll(UnicodeString("<$3$2$1${one}>"), status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(UnicodeString("a<yxmm>z") == replacedText);
+
+ status = U_ZERO_ERROR;
+ replacedText = m->replaceAll(UnicodeString("$3$2$1${one}"), status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(UnicodeString("ayxmmz") == replacedText);
+
+ status = U_ZERO_ERROR;
+ replacedText = m->replaceAll(UnicodeString("<${noSuchName}>"), status);
+ REGEX_ASSERT(status == U_REGEX_INVALID_CAPTURE_GROUP_NAME);
+
+ status = U_ZERO_ERROR;
+ replacedText = m->replaceAll(UnicodeString("<${invalid-name}>"), status);
+ REGEX_ASSERT(status == U_REGEX_INVALID_CAPTURE_GROUP_NAME);
+
+ status = U_ZERO_ERROR;
+ replacedText = m->replaceAll(UnicodeString("<${one"), status);
+ REGEX_ASSERT(status == U_REGEX_INVALID_CAPTURE_GROUP_NAME);
+
+ status = U_ZERO_ERROR;
+ replacedText = m->replaceAll(UnicodeString("$not a capture group"), status);
+ REGEX_ASSERT(status == U_REGEX_INVALID_CAPTURE_GROUP_NAME);
+
+ delete m;
+
+ // Repeat the above replaceAll() tests using the plain C API, which
+ // has a separate implementation internally.
+ // TODO: factor out the test data.
+
+ status = U_ZERO_ERROR;
+ URegularExpression *re = uregex_openC("..(?<one>m)(.)(.)", 0, NULL, &status);
+ REGEX_CHECK_STATUS;
+ text = UnicodeString("abcmxyz");
+ uregex_setText(re, text.getBuffer(), text.length(), &status);
+ REGEX_CHECK_STATUS;
+
+ UChar resultBuf[100];
+ int32_t resultLength;
+ UnicodeString repl;
+
+ status = U_ZERO_ERROR;
+ repl = UnicodeString("<$0>");
+ resultLength = uregex_replaceAll(re, repl.getBuffer(), repl.length(), resultBuf, UPRV_LENGTHOF(resultBuf), &status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(UnicodeString("a<bcmxy>z") == UnicodeString(resultBuf, resultLength));
+
+ status = U_ZERO_ERROR;
+ repl = UnicodeString("<$1>");
+ resultLength = uregex_replaceAll(re, repl.getBuffer(), repl.length(), resultBuf, UPRV_LENGTHOF(resultBuf), &status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(UnicodeString("a<m>z") == UnicodeString(resultBuf, resultLength));
+
+ status = U_ZERO_ERROR;
+ repl = UnicodeString("<${one}>");
+ resultLength = uregex_replaceAll(re, repl.getBuffer(), repl.length(), resultBuf, UPRV_LENGTHOF(resultBuf), &status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(UnicodeString("a<m>z") == UnicodeString(resultBuf, resultLength));
+
+ status = U_ZERO_ERROR;
+ repl = UnicodeString("<$2>");
+ resultLength = uregex_replaceAll(re, repl.getBuffer(), repl.length(), resultBuf, UPRV_LENGTHOF(resultBuf), &status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(UnicodeString("a<x>z") == UnicodeString(resultBuf, resultLength));
+
+ status = U_ZERO_ERROR;
+ repl = UnicodeString("<$3>");
+ resultLength = uregex_replaceAll(re, repl.getBuffer(), repl.length(), resultBuf, UPRV_LENGTHOF(resultBuf), &status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(UnicodeString("a<y>z") == UnicodeString(resultBuf, resultLength));
+
+ status = U_ZERO_ERROR;
+ repl = UnicodeString("<$4>");
+ resultLength = uregex_replaceAll(re, repl.getBuffer(), repl.length(), resultBuf, UPRV_LENGTHOF(resultBuf), &status);
+ REGEX_ASSERT(status == U_INDEX_OUTOFBOUNDS_ERROR);
+
+ status = U_ZERO_ERROR;
+ repl = UnicodeString("<$04>");
+ resultLength = uregex_replaceAll(re, repl.getBuffer(), repl.length(), resultBuf, UPRV_LENGTHOF(resultBuf), &status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(UnicodeString("a<bcmxy4>z") == UnicodeString(resultBuf, resultLength));
+
+ status = U_ZERO_ERROR;
+ repl = UnicodeString("<$000016>");
+ resultLength = uregex_replaceAll(re, repl.getBuffer(), repl.length(), resultBuf, UPRV_LENGTHOF(resultBuf), &status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(UnicodeString("a<m6>z") == UnicodeString(resultBuf, resultLength));
+
+ status = U_ZERO_ERROR;
+ repl = UnicodeString("<$3$2$1${one}>");
+ resultLength = uregex_replaceAll(re, repl.getBuffer(), repl.length(), resultBuf, UPRV_LENGTHOF(resultBuf), &status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(UnicodeString("a<yxmm>z") == UnicodeString(resultBuf, resultLength));
+
+ status = U_ZERO_ERROR;
+ repl = UnicodeString("$3$2$1${one}");
+ resultLength = uregex_replaceAll(re, repl.getBuffer(), repl.length(), resultBuf, UPRV_LENGTHOF(resultBuf), &status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(UnicodeString("ayxmmz") == UnicodeString(resultBuf, resultLength));
+
+ status = U_ZERO_ERROR;
+ repl = UnicodeString("<${noSuchName}>");
+ resultLength = uregex_replaceAll(re, repl.getBuffer(), repl.length(), resultBuf, UPRV_LENGTHOF(resultBuf), &status);
+ REGEX_ASSERT(status == U_REGEX_INVALID_CAPTURE_GROUP_NAME);
+
+ status = U_ZERO_ERROR;
+ repl = UnicodeString("<${invalid-name}>");
+ resultLength = uregex_replaceAll(re, repl.getBuffer(), repl.length(), resultBuf, UPRV_LENGTHOF(resultBuf), &status);
+ REGEX_ASSERT(status == U_REGEX_INVALID_CAPTURE_GROUP_NAME);
+
+ status = U_ZERO_ERROR;
+ repl = UnicodeString("<${one");
+ resultLength = uregex_replaceAll(re, repl.getBuffer(), repl.length(), resultBuf, UPRV_LENGTHOF(resultBuf), &status);
+ REGEX_ASSERT(status == U_REGEX_INVALID_CAPTURE_GROUP_NAME);
+
+ status = U_ZERO_ERROR;
+ repl = UnicodeString("$not a capture group");
+ resultLength = uregex_replaceAll(re, repl.getBuffer(), repl.length(), resultBuf, UPRV_LENGTHOF(resultBuf), &status);
+ REGEX_ASSERT(status == U_REGEX_INVALID_CAPTURE_GROUP_NAME);
+
+ uregex_close(re);
+}
+
+//--------------------------------------------------------------
+//
+// NamedCaptureLimits Patterns with huge numbers of named capture groups.
+// The point is not so much what the exact limit is,
+// but that a largish number doesn't hit bad non-linear performance,
+// and that exceeding the limit fails cleanly.
+//
+//--------------------------------------------------------------
+void RegexTest::NamedCaptureLimits() {
+ if (quick) {
+ logln("Skipping test. Runs in exhuastive mode only.");
+ return;
+ }
+ const int32_t goodLimit = 1000000; // Pattern w this many groups builds successfully.
+ const int32_t failLimit = 10000000; // Pattern exceeds internal limits, fails to compile.
+ char nnbuf[100];
+ UnicodeString pattern;
+ int32_t nn;
+
+ for (nn=1; nn<goodLimit; nn++) {
+ sprintf(nnbuf, "(?<nn%d>)", nn);
+ pattern.append(UnicodeString(nnbuf, -1, US_INV));
+ }
+ UErrorCode status = U_ZERO_ERROR;
+ RegexPattern *pat = RegexPattern::compile(pattern, 0, status);
+ REGEX_CHECK_STATUS;
+ for (nn=1; nn<goodLimit; nn++) {
+ sprintf(nnbuf, "nn%d", nn);
+ int32_t groupNum = pat->groupNumberFromName(nnbuf, -1, status);
+ REGEX_ASSERT(nn == groupNum);
+ if (nn != groupNum) {
+ break;
+ }
+ }
+ delete pat;
+
+ pattern.remove();
+ for (nn=1; nn<failLimit; nn++) {
+ sprintf(nnbuf, "(?<nn%d>)", nn);
+ pattern.append(UnicodeString(nnbuf, -1, US_INV));
+ }
+ status = U_ZERO_ERROR;
+ pat = RegexPattern::compile(pattern, 0, status);
+ REGEX_ASSERT(status == U_REGEX_PATTERN_TOO_BIG);
+ delete pat;
+}
+
+
//--------------------------------------------------------------
//
// Bug7651 Regex pattern that exceeds default operator stack depth in matcher.
delete m;
}
+// Bug 8479: was crashing whith a Bogus UnicodeString as input.
-
+void RegexTest::Bug8479() {
+ UErrorCode status = U_ZERO_ERROR;
-#endif /* !UCONFIG_NO_REGULAR_EXPRESSIONS */
+ RegexMatcher* const pMatcher = new RegexMatcher("\\Aboo\\z", UREGEX_DOTALL|UREGEX_CASE_INSENSITIVE, status);
+ REGEX_CHECK_STATUS;
+ if (U_SUCCESS(status))
+ {
+ UnicodeString str;
+ str.setToBogus();
+ pMatcher->reset(str);
+ status = U_ZERO_ERROR;
+ pMatcher->matches(status);
+ REGEX_ASSERT(status == U_ILLEGAL_ARGUMENT_ERROR);
+ delete pMatcher;
+ }
+}
+
+
+// Bug 7029
+void RegexTest::Bug7029() {
+ UErrorCode status = U_ZERO_ERROR;
+ RegexMatcher* const pMatcher = new RegexMatcher(".", 0, status);
+ UnicodeString text = "abc.def";
+ UnicodeString splits[10];
+ REGEX_CHECK_STATUS;
+ int32_t numFields = pMatcher->split(text, splits, 10, status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(numFields == 8);
+ delete pMatcher;
+}
+
+// Bug 9283
+// This test is checking for the existance of any supplemental characters that case-fold
+// to a bmp character.
+//
+// At the time of this writing there are none. If any should appear in a subsequent release
+// of Unicode, the code in regular expressions compilation that determines the longest
+// posssible match for a literal string will need to be enhanced.
+//
+// See file regexcmp.cpp, case URX_STRING_I in RegexCompile::maxMatchLength()
+// for details on what to do in case of a failure of this test.
+//
+void RegexTest::Bug9283() {
+#if !UCONFIG_NO_NORMALIZATION
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeSet supplementalsWithCaseFolding("[[:CWCF:]&[\\U00010000-\\U0010FFFF]]", status);
+ REGEX_CHECK_STATUS;
+ int32_t index;
+ UChar32 c;
+ for (index=0; ; index++) {
+ c = supplementalsWithCaseFolding.charAt(index);
+ if (c == -1) {
+ break;
+ }
+ UnicodeString cf = UnicodeString(c).foldCase();
+ REGEX_ASSERT(cf.length() >= 2);
+ }
+#endif /* #if !UCONFIG_NO_NORMALIZATION */
+}
+
+
+void RegexTest::CheckInvBufSize() {
+ if(inv_next>=INV_BUFSIZ) {
+ errln("%s: increase #define of INV_BUFSIZ ( is %d but needs to be at least %d )\n",
+ __FILE__, INV_BUFSIZ, inv_next);
+ } else {
+ logln("%s: INV_BUFSIZ is %d, usage %d\n", __FILE__, INV_BUFSIZ, inv_next);
+ }
+}
+
+
+void RegexTest::Bug10459() {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString patternString("(txt)");
+ UnicodeString txtString("txt");
+
+ UText *utext_pat = utext_openUnicodeString(NULL, &patternString, &status);
+ REGEX_CHECK_STATUS;
+ UText *utext_txt = utext_openUnicodeString(NULL, &txtString, &status);
+ REGEX_CHECK_STATUS;
+
+ URegularExpression *icu_re = uregex_openUText(utext_pat, 0, NULL, &status);
+ REGEX_CHECK_STATUS;
+
+ uregex_setUText(icu_re, utext_txt, &status);
+ REGEX_CHECK_STATUS;
+
+ // The bug was that calling uregex_group() before doing a matching operation
+ // was causing a segfault. Only for Regular Expressions created from UText.
+ // It should set an U_REGEX_INVALID_STATE.
+
+ UChar buf[100];
+ int32_t len = uregex_group(icu_re, 0, buf, UPRV_LENGTHOF(buf), &status);
+ REGEX_ASSERT(status == U_REGEX_INVALID_STATE);
+ REGEX_ASSERT(len == 0);
+
+ uregex_close(icu_re);
+ utext_close(utext_pat);
+ utext_close(utext_txt);
+}
+
+void RegexTest::TestCaseInsensitiveStarters() {
+ // Test that the data used by RegexCompile::findCaseInsensitiveStarters() hasn't
+ // become stale because of new Unicode characters.
+ // If it is stale, rerun the generation tool
+ // svn+ssh://source.icu-project.org/repos/icu/tools/trunk/unicode/c/genregexcasing
+ // and replace the embedded data in i18n/regexcmp.cpp
+
+ for (UChar32 cp=0; cp<=0x10ffff; cp++) {
+ if (!u_hasBinaryProperty(cp, UCHAR_CASE_SENSITIVE)) {
+ continue;
+ }
+ UnicodeSet s(cp, cp);
+ s.closeOver(USET_CASE_INSENSITIVE);
+ UnicodeSetIterator setIter(s);
+ while (setIter.next()) {
+ if (!setIter.isString()) {
+ continue;
+ }
+ const UnicodeString &str = setIter.getString();
+ UChar32 firstChar = str.char32At(0);
+ UnicodeSet starters;
+ RegexCompile::findCaseInsensitiveStarters(firstChar, &starters);
+ if (!starters.contains(cp)) {
+ errln("CaseInsensitiveStarters for \\u%x is missing character \\u%x.", cp, firstChar);
+ return;
+ }
+ }
+ }
+}
+
+
+void RegexTest::TestBug11049() {
+ // Original bug report: pattern with match start consisting of one of several individual characters,
+ // and the text being matched ending with a supplementary character. find() would read past the
+ // end of the input text when searching for potential match starting points.
+
+ // To see the problem, the text must exactly fill an allocated buffer, so that valgrind will
+ // detect the bad read.
+
+ TestCase11049("A|B|C", "a string \\ud800\\udc00", FALSE, __LINE__);
+ TestCase11049("A|B|C", "string matches at end C", TRUE, __LINE__);
+
+ // Test again with a pattern starting with a single character,
+ // which takes a different code path than starting with an OR expression,
+ // but with similar logic.
+ TestCase11049("C", "a string \\ud800\\udc00", FALSE, __LINE__);
+ TestCase11049("C", "string matches at end C", TRUE, __LINE__);
+}
+
+// Run a single test case from TestBug11049(). Internal function.
+void RegexTest::TestCase11049(const char *pattern, const char *data, UBool expectMatch, int32_t lineNumber) {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString patternString = UnicodeString(pattern).unescape();
+ LocalPointer<RegexPattern> compiledPat(RegexPattern::compile(patternString, 0, status));
+
+ UnicodeString dataString = UnicodeString(data).unescape();
+ UChar *exactBuffer = new UChar[dataString.length()];
+ dataString.extract(exactBuffer, dataString.length(), status);
+ UText *ut = utext_openUChars(NULL, exactBuffer, dataString.length(), &status);
+
+ LocalPointer<RegexMatcher> matcher(compiledPat->matcher(status));
+ REGEX_CHECK_STATUS;
+ matcher->reset(ut);
+ UBool result = matcher->find();
+ if (result != expectMatch) {
+ errln("File %s, line %d: expected %d, got %d. Pattern = \"%s\", text = \"%s\"",
+ __FILE__, lineNumber, expectMatch, result, pattern, data);
+ }
+
+ // Rerun test with UTF-8 input text. Won't see buffer overreads, but could see
+ // off-by-one on find() with match at the last code point.
+ // Size of the original char * data (invariant charset) will be <= than the equivalent UTF-8
+ // because string.unescape() will only shrink it.
+ char * utf8Buffer = new char[uprv_strlen(data)+1];
+ u_strToUTF8(utf8Buffer, uprv_strlen(data)+1, NULL, dataString.getBuffer(), dataString.length(), &status);
+ REGEX_CHECK_STATUS;
+ ut = utext_openUTF8(ut, utf8Buffer, -1, &status);
+ REGEX_CHECK_STATUS;
+ matcher->reset(ut);
+ result = matcher->find();
+ if (result != expectMatch) {
+ errln("File %s, line %d (UTF-8 check): expected %d, got %d. Pattern = \"%s\", text = \"%s\"",
+ __FILE__, lineNumber, expectMatch, result, pattern, data);
+ }
+ delete [] utf8Buffer;
+
+ utext_close(ut);
+ delete [] exactBuffer;
+}
+
+
+void RegexTest::TestBug11371() {
+ if (quick) {
+ logln("Skipping test. Runs in exhuastive mode only.");
+ return;
+ }
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString patternString;
+
+ for (int i=0; i<8000000; i++) {
+ patternString.append(UnicodeString("()"));
+ }
+ LocalPointer<RegexPattern> compiledPat(RegexPattern::compile(patternString, 0, status));
+ if (status != U_REGEX_PATTERN_TOO_BIG) {
+ errln("File %s, line %d expected status=U_REGEX_PATTERN_TOO_BIG; got %s.",
+ __FILE__, __LINE__, u_errorName(status));
+ }
+
+ status = U_ZERO_ERROR;
+ patternString = "(";
+ for (int i=0; i<20000000; i++) {
+ patternString.append(UnicodeString("A++"));
+ }
+ patternString.append(UnicodeString("){0}B++"));
+ LocalPointer<RegexPattern> compiledPat2(RegexPattern::compile(patternString, 0, status));
+ if (status != U_REGEX_PATTERN_TOO_BIG) {
+ errln("File %s, line %d expected status=U_REGEX_PATTERN_TOO_BIG; got %s.",
+ __FILE__, __LINE__, u_errorName(status));
+ }
+
+ // Pattern with too much string data, such that string indexes overflow operand data field size
+ // in compiled instruction.
+ status = U_ZERO_ERROR;
+ patternString = "";
+ while (patternString.length() < 0x00ffffff) {
+ patternString.append(UnicodeString("stuff and things dont you know, these are a few of my favorite strings\n"));
+ }
+ patternString.append(UnicodeString("X? trailing string"));
+ LocalPointer<RegexPattern> compiledPat3(RegexPattern::compile(patternString, 0, status));
+ if (status != U_REGEX_PATTERN_TOO_BIG) {
+ errln("File %s, line %d expected status=U_REGEX_PATTERN_TOO_BIG; got %s.",
+ __FILE__, __LINE__, u_errorName(status));
+ }
+}
+
+void RegexTest::TestBug11480() {
+ // C API, get capture group of a group that does not participate in the match.
+ // (Returns a zero length string, with nul termination,
+ // indistinguishable from a group with a zero lenght match.)
+
+ UErrorCode status = U_ZERO_ERROR;
+ URegularExpression *re = uregex_openC("(A)|(B)", 0, NULL, &status);
+ REGEX_CHECK_STATUS;
+ UnicodeString text = UNICODE_STRING_SIMPLE("A");
+ uregex_setText(re, text.getBuffer(), text.length(), &status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(uregex_lookingAt(re, 0, &status));
+ UChar buf[10] = {(UChar)13, (UChar)13, (UChar)13, (UChar)13};
+ int32_t length = uregex_group(re, 2, buf+1, UPRV_LENGTHOF(buf)-1, &status);
+ REGEX_ASSERT(length == 0);
+ REGEX_ASSERT(buf[0] == 13);
+ REGEX_ASSERT(buf[1] == 0);
+ REGEX_ASSERT(buf[2] == 13);
+ uregex_close(re);
+}
+
+
+#endif /* !UCONFIG_NO_REGULAR_EXPRESSIONS */