8

экспрессирующих двигателями Очередными есть понятие «нулевая ширина» матчи, некоторые из которых являются полезными для поиска краев слов:Регулярного выражения для сравнения границы между различными Unicode скриптами

  • \b - в настоящее время в большинстве двигателей соответствуют любая граница между словами и несловными символами
  • \< and \> - present in Vim соответствует только границе в начале слова и в конце слова, соответственно.

Более новая концепция в некоторых машинах с регулярным выражением - это классы Unicode. Один из таких классов является сценарий, который может отличить латинский, греческий, кириллица и т.д. Эти примеры эквивалентны и любой символ греческой письменности:

  • \p{greek}
  • \p{script=greek}
  • \p{script:greek}
  • [:script=greek:]
  • [:script:greek:]

Но пока я читал источники по регулярным выражениям и Unicode, я не смог определить, существует ли какой-либо стандартный или нестандартный способ достижения соответствия нулевой ширины, когда один скрипт заканчивается, а другой начинается.

В строке παν語 был бы матч между ν и персонажами, так же, как и \b\< будет соответствовать как раз перед π характером.

Теперь для этого примера я мог бы взломать что-то вместе на основе поиска \p{Greek}, за которым следует \p{Han}, и я мог бы даже взломать что-то вместе на основе всех возможных комбинаций двух имен сценариев Unicode.

Но это не будет детерминированным решением, так как новые скрипты все еще добавляются в Unicode с каждой версией. Есть ли способ для будущего, чтобы выразить это? Или есть предложение добавить его?

+2

Закрыть, но не совсем то же самое: http://stackoverflow.com/questions/14942652/how-to-emulate-word-boundary-when-using-unicode-character-properties/14942906#14942906 Мой ответ - это граница для один класс символов (и это относится к любому классу символов). Ваш вопрос о границе между любым языком. – nhahtdh

+0

@nhahtdh: Спасибо. Я удивлен, что не нашел ваш вопрос в своих поисках. – hippietrail

+1

Я думаю, что каждый должен прочитать раздел 2 этого: http://www.unicode.org/reports/tr24/ – nhahtdh

ответ

3

EDIT: Я просто заметил, что вы на самом деле не указать который шаблон сопоставления языка вы использовали. Ну, я надеюсь, что решение Perl будет работать для вас, так как необходимые механики, вероятно, будут очень жесткими на любом другом языке. Плюс, если вы выполняете сопоставление с Unicode, Perl действительно лучший выбор для этой конкретной работы.


Когда переменная $rx ниже устанавливается в соответствующий шаблон, этот маленький фрагмент кода Perl:

my $data = "foo1 and Πππ 語語語 done"; 

while ($data =~ /($rx)/g) { 
    print "Got string: '$1'\n"; 
} 

Формирует этот вывод:

Got string: 'foo1 and ' 
Got string: 'Πππ ' 
Got string: '語語語 ' 
Got string: 'done' 

То есть, он вытаскивает латинскую строку, греческую строку, строку Han и другую латинскую строку.Это довольно чертово, закрытое для того, что, на мой взгляд, вам действительно нужно.

Причина, по которой я не опубликовал это вчера, заключается в том, что я получаю странные отвалы ядра. Теперь я знаю, почему.

В моем решении используются лексические переменные внутри конструкции (??{...}). Оказывается, что это неустойчиво до v5.17.1, и в лучшем случае работает только случайно. Он не работает на v5.17.0, но преуспевает в v5.18.0 RC0 и RC2. Поэтому я добавил use v5.17.1, чтобы убедиться, что вы используете что-то достаточно недавнее, чтобы доверять этому подходу.

Во-первых, я решил, что вы действительно не хотите запускать все те же типы скриптов; вам нужен запуск всего того же типа скрипта плюс Обычный и унаследованный. В противном случае вы будете испорчены пунктуацией, пробелами и цифрами для Common, и комбинируя символы для Inherited. Я действительно не думаю, что вы хотите, чтобы те прервали ваш запуск «все того же скрипта», но если вы это сделаете, легко перестать рассматривать их.

Так что мы делаем это для первого символа, который имеет тип скрипта, отличный от Common или Inherited. Более того, мы извлекаем из него то, что на самом деле этот тип сценария, и используем эту информацию для создания нового шаблона, который представляет собой любое количество символов, тип сценария которых является либо общим, либо унаследованным, либо любым типом скрипта, который мы только что нашли и сохранили. Затем мы оцениваем этот новый шаблон и продолжаем.

Hey, I Это было волосатое, не так ли?

В программе, которую я собираюсь показать, я оставил в некоторых комментариях отладочные заявления, которые показывают только, что он делает. Если вы раскомментировать их, вы получите этот выход для последнего запуска, который должен помочь понять подход:

DEBUG: Got peekahead character f, U+0066 
DEBUG: Scriptname is Latin 
DEBUG: string to re-interpolate as regex is q{[\p{Script=Common}\p{Script=Inherited}\p{Script=Latin}]*} 
Got string: 'foo1 and ' 
DEBUG: Got peekahead character Π, U+03a0 
DEBUG: Scriptname is Greek 
DEBUG: string to re-interpolate as regex is q{[\p{Script=Common}\p{Script=Inherited}\p{Script=Greek}]*} 
Got string: 'Πππ ' 
DEBUG: Got peekahead character 語, U+8a9e 
DEBUG: Scriptname is Han 
DEBUG: string to re-interpolate as regex is q{[\p{Script=Common}\p{Script=Inherited}\p{Script=Han}]*} 
Got string: '語語語 ' 
DEBUG: Got peekahead character d, U+0064 
DEBUG: Scriptname is Latin 
DEBUG: string to re-interpolate as regex is q{[\p{Script=Common}\p{Script=Inherited}\p{Script=Latin}]*} 
Got string: 'done' 

И вот наконец это большие волосатые сделки:

use v5.17.1; 
use strict; 
use warnings; 
use warnings FATAL => "utf8"; 
use open qw(:std :utf8); 
use utf8; 

use Unicode::UCD qw(charscript); 

# regex to match a string that's all of the 
# same Script=XXX type 
# 
my $rx = qr{ 
    (?= 
     [\p{Script=Common}\p{Script=Inherited}] * 
     (?<CAPTURE> 
      [^\p{Script=Common}\p{Script=Inherited}] 
     ) 
    ) 
    (??{ 
     my $capture = $+{CAPTURE}; 
    #####printf "DEBUG: Got peekahead character %s, U+%04x\n", $capture, ord $capture; 
     my $scriptname = charscript(ord $capture); 
    #####print "DEBUG: Scriptname is $scriptname\n"; 
     my $run = q([\p{Script=Common}\p{Script=Inherited}\p{Script=) 
       . $scriptname 
       . q(}]*); 
    #####print "DEBUG: string to re-interpolate as regex is q{$run}\n"; 
     $run; 
    }) 
}x; 


my $data = "foo1 and Πππ 語語語 done"; 

$| = 1; 

while ($data =~ /($rx)/g) { 
    print "Got string: '$1'\n"; 
} 

Да, там Oughta быть лучший способ. Я не думаю, что есть.

Так что пока, наслаждайтесь.

+0

О, я конкретно не указывал диалект регулярного выражения, скорее я спросил о «стандартном», «нестандартном» и «предлагаемом». Я на самом деле играю с XRegExp и читаю через UTS # 18 и regular-expressions.info, но я больше привык к реализациям Perl и Vim. Наверное, я хочу знать, что я должен делать, даже если конкретные диалекты еще не реализовали его. Для обходных решений я предполагаю, что JavaScript или даже расширение для XRegExp было бы лучше. (Я пишу это, прежде чем читать тело вашего ответа, кстати ...) – hippietrail

+1

@hippietrail UTS # 18 не будет охватывать это, пока, по крайней мере, уровень 3, и никто пока не реализует это. Поэтому мы делаем то, что можем, между тем. Я на самом деле не смотрел его в последнее время, поэтому не знаю, возможно ли это на уровне 3. – tchrist

+0

Помимо себя, конечно, кто активно продвигает развитие регулярного выражения Unicode в наши дни? Я знаю, что Perl на сегодняшний день является лучшей поддержкой Unicode, и это одна из главных причин, по которой это был мой основной язык в течение многих лет, но теперь я перешел по другим причинам на язык с некоторой худшей поддержкой Unicode. Я могу определенно придумать разделитель строк без регулярных выражений, но он казался очевидной функцией включения в механизм регулярных выражений. Может быть, я должен представить некоторые предложения? – hippietrail

Смежные вопросы