<font face="georgia,serif">The Unicode Standard distinguishes between Unicode Strings (16-bit) and UTF-16. In the former, which is often the form used in programming languages, a singleton value of 0xD800..0xDFFF is allowed, and is treated as if it were a reserved code point.</font><div>
<font face="georgia,serif"><br></font></div><div><font face="georgia,serif">So you do get some funny cases, because </font></div><div><ol><li><span class="Apple-style-span" style="font-family: georgia, serif; ">0xD800 - 1 code point (degenerate surrogate)</span></li>
<li><font face="georgia,serif"><meta charset="utf-8">0xDC00 - 1 code point</font><span class="Apple-style-span" style="font-family: georgia, serif; "> (degenerate surrogate)</span></li><li><span class="Apple-style-span" style="font-family: georgia, serif; "><meta charset="utf-8">0xD800 <meta charset="utf-8">0xDC00 - 1 code point (surrogate pair)</span></li>
<li><span class="Apple-style-span" style="font-family: georgia, serif; "><meta charset="utf-8">0xDC00 <meta charset="utf-8">0xD800 - 2 code points (2 successive degenerate surrogates).</span></li></ol></div><meta charset="utf-8"><div>
<span class="Apple-style-span" style="font-family: georgia, serif; ">If you are working in UTF-8 or in UTF-32, then these cases wouldn&#39;t occur. They can&#39;t happen in UTF-8, and in UTF-32 both cases 3 and 4 are </span><span class="Apple-style-span" style="font-family: georgia, serif; ">2 successive degenerate surrogates.</span></div>
<meta charset="utf-8"><div><font face="georgia,serif"><br clear="all"></font><font face="georgia, serif">Mark<br><br><i>— Il meglio è l’inimico del bene —</i></font><br>
<br><br><div class="gmail_quote">On Sat, Jan 22, 2011 at 19:54, Tom Christiansen <span dir="ltr">&lt;<a href="mailto:tchrist@perl.com">tchrist@perl.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
Sherman,<br>
<br>
In part 1, I outlined my thinking of why having to make end-users think<br>
about represenation issues in regexes goes against if not perhaps the law,<br>
certainly to mind the spirit of UTS(tr)#18 when it says that a compliant<br>
&quot;the regular expression engine provides support for Unicode characters as<br>
basic logical units.&quot;<br>
<br>
Please understand that I don&#39;t think that is much of a big deal -- it&#39;s a<br>
rather low priority bug at worse -- because when you look at it from a<br>
particular perspective, it appears to be a surface-level matter only.<br>
<br>
(Also because it is easily addressed just by adding \x{XXX}, which is<br>
both simple and safe.)<br>
<br>
It&#39;s not that big of a deal because as you yourself point out, Sherman, you<br>
can still specify any code point, although you have to bend over sideways<br>
to do it.  But it doesn&#39;t at all affect behaviour, which is by far the more<br>
important matter.<br>
<br>
These next two serialization concerns, however, are different. This time<br>
they are not just surface issues.  They are actual behavioral problems in<br>
regexes that  derive from the actual internal implementation of characters<br>
in Java:<br>
<br>
  **  Surrogate Bugs in Regexes<br>
<br>
  **  CANON_EQ Bugs in Regexes with \\uXXXX<br>
<br>
I don&#39;t think users should have to know about those implementational<br>
details, but if they don&#39;t, they will get several sorts of anomalous<br>
behaviour.  I therefore believe those two are both geniuine bugs.<br>
<br>
I know exactly what is causing the second one (code included), but<br>
fixing it is going to require some code rearrangement and reworking.<br>
<br>
===========================<br>
 Surrogate Bugs in Regexes<br>
===========================<br>
<br>
Here is one of them:<br>
<br>
    Unicode       UTF-16<br>
   Code Point     String            Pattern     Result<br>
   =========   ==============      =========    ======<br>
    U+1F47E    &quot;\uD83D\uDC7E&quot;       /^.$/       true<br>
     n/a       &quot;\uD83D&quot;             /^.$/       TRUE!<br>
<br>
I do not understand how that same pattern--which says to match<br>
strings containing a single Unicode code point only--can test on<br>
both those strings.  That&#39;s why I believe the TRUE! result an error.<br>
<br>
Don&#39;t you?<br>
<br>
I understand that it brings up some tricky stuff.  Consider:<br>
<br>
    If you have a string &quot;HL&quot; where H is a high surrogate and L a low<br>
    surrogate, Java&#39;s regex engine correctly concludes that that string<br>
    &quot;HL&quot; exactly matches the pattern &quot;^.$&quot; in its entirety; it has just one<br>
    logical character in it.   This is correct.  It fails to match &quot;^..$&quot;,<br>
    which is also correct and for the same reason.<br>
<br>
    However, if you flip those around to get string &quot;LH&quot;, it now exactly<br>
    matches the pattern &quot;^..$&quot; in its entirety, thus claiming it holds<br>
    exactly two characters even there are no legal<br>
    code points there!<br>
<br>
    If you have just one of the two surrogates, either &quot;H&quot; or &quot;L&quot;, both of<br>
    those will also match &quot;^.$&quot; just as &quot;HL&quot; does.  That says that a single<br>
    surrogate is just as much a single logical character as a proper pair<br>
    of them together is just a single logical character.<br>
<br>
But that makes no senses at all.  How can both be correct?  Surely that<br>
*must* be a bug?  What am I not understanding here?<br>
<br>
I really think that rather than returning true for something that<br>
isn&#39;t even a legal Unicode code point, it should instead either<br>
<br>
    1: raise an exception<br>
<br>
and/or<br>
<br>
    2: admit some pattern flag to deal with such cases<br>
<br>
I say this because you are not supposed to have to deal representation<br>
and serialization issues in regexes, and this makes you think about them.<br>
It also gives you bizarre answers even when you do think about them.<br>
<br>
=======================================<br>
 CANON_EQ Bugs in Regexes with \\uXXXX<br>
=======================================<br>
<br>
Another place where you are forced to think about the internal<br>
representation in Java regexes, is that they can behave differently if<br>
you pass things in as &quot;\\uXXXX&quot; instead of as &quot;\uXXXX&quot;.  I don&#39;t think<br>
that can be correct behaviour, either.<br>
<br>
The problem is that the CANON_EQ can no longer be trusted.  If you compile<br>
up these patterns with CANON_EQ, then it makes a difference whether you&#39;ve<br>
used a literal or a \u0000 form.  Please consider these, as I believe that<br>
FALSE! results below are all in error:<br>
<br>
        String          Pattern<br>
                       w/CANON_EQ           Result<br>
        =========     ============        =========<br>
     A : &quot;\u00E9&quot;       &quot;^\u00E9$&quot;          true<br>
     B : &quot;\u00E9&quot;       &quot;^e\u0301$&quot;         true<br>
     A&#39;: &quot;\u00E9&quot;       &quot;^\\u00E9$&quot;         true<br>
     B&#39;: &quot;\u00E9&quot;       &quot;^e\\u0301$&quot;        FALSE!<br>
<br>
     C : &quot;e\u0301&quot;      &quot;^\u00E9$&quot;          true<br>
     D : &quot;e\u0301&quot;      &quot;^e\u0301$&quot;         true<br>
     C&#39;: &quot;e\u0301&quot;      &quot;^\\u00E9$&quot;         FALSE!<br>
     D&#39;: &quot;e\u0301&quot;      &quot;^e\\u0301$&quot;        true<br>
<br>
The ABCD versions all use literals converted during the lexical<br>
substitution phase, whereas the prime versions use UTF-16 code<br>
units that get passed into the regex compiler for it to consider.<br>
<br>
(This second mechanism is indispensable to meet the requirement<br>
of being able to code up any code point, and to facilitate reading<br>
patterns written in ASCII but specifying trans-ASCII code points.)<br>
<br>
You get the same problem with octal notation: you can specify U+E9 as<br>
&quot;\351&quot; for the prepass literal (which works), or as &quot;\\0351&quot; for the<br>
regex engine to see (which fails just as \\u did):<br>
<br>
        String          Pattern<br>
                       w/CANON_EQ           Result<br>
        =========     ============        =========<br>
     a : &quot;\u00E9&quot;       &quot;^\351$&quot;            true<br>
     a&#39;: &quot;\u00E9&quot;       &quot;^\\0351$&quot;          true<br>
     c : &quot;e\u0301&quot;      &quot;^\351$&quot;            true<br>
     c&#39;: &quot;e\u0301&quot;      &quot;^\\0351$&quot;          FALSE!<br>
<br>
As you might predict, using UTF-8 directly in your code and compiling with<br>
&quot;java -encoding UTF-8&quot; behaves exactly as the non-prime &quot;\uXXXX&quot; versions<br>
do, but which can be different from how the prime &quot;\\uXXXX&quot; version behave.<br>
<br>
&gt;From looking at the code, I am sure I can reproduce this with \xXX escapes<br>
as well.  That&#39;s because you do the normalization reshuffle before you<br>
actually compile the pattern, so you won&#39;t see the octal or hex escapes<br>
when you&#39;re doing the normalization.  The bug is right here in this code<br>
right here, from around line 1500 of jdk1.7.0/java/util/regex/Pattern.java:<br>
<br>
    /**<br>
     * Copies regular expression to an int array and invokes the parsing<br>
     * of the expression which will create the object tree.<br>
     */<br>
    private void compile() {<br>
        // Handle canonical equivalences<br>
        if (has(CANON_EQ) &amp;&amp; !has(LITERAL)) {<br>
            normalize();<br>
        } else {<br>
            normalizedPattern = pattern;<br>
        }<br>
        patternLength = normalizedPattern.length();<br>
<br>
        // Copy pattern to int array for convenience<br>
        // Use double zero to terminate pattern<br>
        temp = new int[patternLength + 2];<br>
<br>
Because things like \cC and \0XXX and \xXX and \uXXXX all get handled<br>
*after* that point in the code, they are *not* the same as literals with<br>
those values.  This is a genuine problem.<br>
<br>
So again we have to think about how things are stored.  It means that<br>
you cannot just read in patterns that have had there non-ASCII converted<br>
into \uXXXX escapes and have them work the same as having the literals in<br>
there.  Those are supposed to be the same as the literals, but they&#39;re not.<br>
<br>
This is quite apart from the--um, &quot;syntactic infelicity&quot;?--of the mismatch<br>
between how octal excapes are specified in the lexical substitution pass<br>
versus how they&#39;re specified in the regex engine.  That, I wouldn&#39;t quite<br>
call a bug so much as an unexpected wrinkle.  I do fix this in my regex<br>
rewriter, BTW.<br>
<br>
    (There are &quot;syntactic infelicities&quot; with \cC, too.  It is a bit too<br>
     undiscerning, producing things that aren&#39;t guaranteed to be control<br>
     characters because it blindly xors whatever follows it with 64.  For<br>
     example, \c} is = and \c= is }, \cé is © and \c© is é, etc. )<br>
<br>
This is message is far too long again, so I will discuss your comments<br>
regarding the j.l.Character class in part 3 of 3, to be sent later on.<br>
<br>
Thanks again!<br>
<font color="#888888"><br>
--tom<br>
</font></blockquote></div><br></div>