EDIT: Ho appena notato che non ha in realtà specificato che lingua pattern-matching si stava utilizzando. Bene, spero che una soluzione Perl funzioni per te, dal momento che le meccaniche necessarie sono molto difficili in qualsiasi altra lingua. Inoltre, se stai realizzando pattern matching con Unicode, Perl è davvero la scelta migliore disponibile per quel particolare tipo di lavoro.
Quando la variabile $rx
sotto è impostato sul modello appropriato, questo piccolo frammento di codice Perl:
my $data = "foo1 and Πππ 語語語 done";
while ($data =~ /($rx)/g) {
print "Got string: '$1'\n";
}
genera questo output:
Got string: 'foo1 and '
Got string: 'Πππ '
Got string: '語語語 '
Got string: 'done'
Cioè, si tira fuori una stringa latina, una stringa greca, una stringa Han e un'altra stringa latina.Questo è davvero dannatamente chiuso a ciò che penso tu abbia effettivamente bisogno.
Il motivo per cui non l'ho postato ieri è che stavo ottenendo strani core core. Ora so perché.
La mia soluzione utilizza variabili lessicali all'interno di un costrutto (??{...})
. Risulta che è instabile prima di v5.17.1, e nella migliore delle ipotesi ha funzionato solo per sbaglio. Fallisce su v5.17.0, ma ha successo su v5.18.0 RC0 e RC2. Quindi ho aggiunto un use v5.17.1
per assicurarmi che tu stia eseguendo qualcosa di abbastanza recente da fidarti di questo approccio.
In primo luogo, ho deciso che in realtà non si desidera eseguire un'esecuzione con lo stesso tipo di script; volevi eseguire lo stesso tipo di script più Comune ed Ereditato. Altrimenti verrai incasinato dalla punteggiatura e dagli spazi bianchi e dalle cifre per Common, e combinando i caratteri per Ereditato. Davvero non penso che tu voglia che questi interrompano la tua serie di "tutti gli stessi script", ma se lo fai, è facile smettere di considerarli.
Quindi quello che facciamo è guardare avanti per il primo carattere che ha un tipo di script diverso da Comune o Ereditato. Oltre a ciò, estraiamo da esso ciò che effettivamente è quel tipo di script e usiamo queste informazioni per costruire un nuovo pattern che è un numero qualsiasi di caratteri il cui tipo di script è Common, Ereditato o qualsiasi tipo di script che abbiamo appena trovato e salvato. Quindi valutiamo quel nuovo modello e continuiamo.
Ehi, I ha detto era peloso, no?
Nel programma che sto per mostrare, ho lasciato in alcune dichiarazioni di debug commentate che mostrano solo ciò che sta facendo. Se li si rimuove il commento, si ottiene questa uscita per l'ultima esecuzione, che dovrebbe aiutare a capire l'approccio:
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'
E qui, finalmente è il grosso problema peloso:
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";
}
Sì, ci oughta essere un modo migliore. Non penso ci sia ancora.
Quindi per ora, divertiti.
Chiudi ma non esattamente lo stesso: http://stackoverflow.com/questions/14942652/how-to-emulate-word-boundary-when-using-unicode-character-properties/14942906#14942906 La mia risposta è per una singola classe di caratteri (e questo vale per qualsiasi classe di caratteri). La tua domanda riguarda il confine tra qualsiasi lingua. – nhahtdh
@nhahtdh: Grazie. Sono sorpreso di non aver trovato la tua domanda nella mia ricerca. – hippietrail
Penso che tutti dovrebbero leggere la sezione 2 di questo: http://www.unicode.org/reports/tr24/ – nhahtdh