[Rd] Bug in perl=TRUE regexp matching?
Brodie Gaslam
brod|e@g@@|@m @end|ng |rom y@hoo@com
Tue Jul 25 03:13:36 CEST 2023
On 7/24/23 4:10 AM, Duncan Murdoch wrote:
> On 23/07/2023 9:01 p.m., Brodie Gaslam wrote:
>>
>>
>> On 7/23/23 4:29 PM, Duncan Murdoch wrote:
>>> The help page for `?gsub` says (in the context of performance
>>> considerations):
>>>
>>>
>>> "... just one UTF-8 string will force all the matching to be done in
>>> Unicode"
>>
>> It's been a little while since I looked at the code but IIRC this just
>> means that strings are converted to UTF-8 before matching. The problem
>> here seems to be more about the interpretation of the "\\w+" token by
>> PCRE. I think this makes it a little clearer what's going on:
>>
>> gsub("\\w", "a", "Γ", perl=TRUE)
>> [1] "Γ"
>>
>> So no match. The PCRE docs
>> https://www.pcre.org/original/doc/html/pcrepattern.html (this might be
>> the old docs, but it works for our purposes here) mention we can turn on
>> unicode property matching with the "(*UCP)" token:
>>
>> gsub("(*UCP)\\w", "a", "Γ", perl=TRUE)
>> [1] "a"
>>
>> So there are two layers at play here. The first one is whether R
>> converts strings to UTF-8, which I think is what the documentation is
>> about. The other is whether the PCRE engine is configured to recognize
>> Unicode properties, which at least in both of our configurations for
>> this specific case it appears like it is not.
>
> From the surrounding context, I think the docs are talking about more
> than just conversion to UTF-8. The full paragraph reads like this:
>
> "If you are working in a single-byte locale (though not common since R
> 4.2) and have marked UTF-8 strings that are representable in that
> locale, convert them first as just one UTF-8 string will force all the
> matching to be done in Unicode, which attracts a penalty of around
> 3× for the default POSIX 1003.2 mode."
>
> i.e. it says the presence of UTF-8 strings slows things down by a factor
> of 3, so it's faster to convert everything to the local encoding. If it
> was just conversion, I don't think that would be true.
>
> But maybe "for the default POSIX 1003.2 mode" applies to the whole
> paragraph, not just to the penalty, so this is intentional.
Agreed, I don't think this whole issue is just about the conversion.
What I'm trying to highlight is the distinction between what R does
(converts input to Unicode - UTF-8 for PCRE[1], wchar_t for
POSIX/TRE[2]), and what the regular expression engines then do (match
that Unicode per their own semantics). This for the case of any UTF-8
in the input.
PCRE is behaving as documented[3]:
> By default, characters whose code points are greater than 127 never
match \d, \s, or \w, and always match \D, \S, and \W, although this may
be different for characters in the range 128-255 when locale-specific
matching is happening. These escape sequences retain their original
meanings from before Unicode support was available, mainly for
efficiency reasons. If the PCRE2_UCP option is set, the behaviour is
changed so that Unicode properties are used to determine character
types, as follows...
So this doesn't seem like a bug to me.
Does that mean that the following is incorrect?
> one UTF-8 string will force all the matching to be done in Unicode
It depends on how you want to interpret "done in". Less ambiguous could be:
> one UTF-8 string will force all strings to be converted to Unicode
prior to matching.
Best,
B
[1]:
https://github.com/r-devel/r-svn/blob/a8a3c4d6902525e4222e0bbf5b512f36e2ceac3d/src/main/grep.c#L1385
[2]:
https://github.com/r-devel/r-svn/blob/a8a3c4d6902525e4222e0bbf5b512f36e2ceac3d/src/main/grep.c#L1378
[3]: https://pcre.org/current/doc/html/pcre2pattern.html
>
> Duncan Murdoch
>>
>> Best,
>>
>> B.
>>
>>
>>>
>>>
>>> However, this thread on SO: https://stackoverflow.com/q/76749529 gives
>>> some indication that this is not true for `perl = TRUE`. Specifically:
>>>
>>> > strings <- c("89 562", "John Smith", "Γιάννης Παπαδόπουλος",
>>> "Jean-François Dupuis")
>>> > Encoding(strings)
>>> [1] "unknown" "unknown" "UTF-8" "UTF-8"
>>> > regex <- "\\B\\w+| +"
>>> > gsub(regex, "", strings)
>>> [1] "85" "JS" "ΓΠ" "J-FD"
>>>
>>> > gsub(regex, "", strings, perl = TRUE)
>>> [1] "85" "JS" "ΓιάννηςΠαπαδόπουλος"
>>> "J-FçoD"
>>>
>>> and the website https://regex101.com/r/QDFrOE/1 gives the first answer
>>> when the regex option /u ("match with full Unicode) is specified, but
>>> the second answer when it is not.
>>>
>>> Now I'm not at all sure that that website is authoritative, but this
>>> looks like a flag may have been missed in the `perl = TRUE` case.
>>>
>>> Duncan Murdoch
>>>
>>> ______________________________________________
>>> R-devel using r-project.org mailing list
>>> https://stat.ethz.ch/mailman/listinfo/r-devel
>
More information about the R-devel
mailing list