blib/lib/Lingua/PT/PLNbase.pm | |||
---|---|---|---|
Criterion | Covered | Total | % |
statement | 34 | 532 | 6.3 |
branch | 2 | 100 | 2.0 |
condition | 2 | 49 | 4.0 |
subroutine | 10 | 35 | 28.5 |
pod | 14 | 14 | 100.0 |
total | 62 | 730 | 8.4 |
line | stmt | bran | cond | sub | pod | time | code |
---|---|---|---|---|---|---|---|
1 | package Lingua::PT::PLNbase; | ||||||
2 | |||||||
3 | 8 | 8 | 350204 | use 5.006; | |||
8 | 34 | ||||||
8 | 324 | ||||||
4 | 8 | 8 | 47 | use strict; | |||
8 | 15 | ||||||
8 | 267 | ||||||
5 | 8 | 8 | 42 | use warnings; | |||
8 | 18 | ||||||
8 | 233 | ||||||
6 | 8 | 8 | 14540 | use Data::Dumper; | |||
8 | 109404 | ||||||
8 | 1999 | ||||||
7 | 8 | 8 | 11748 | use Lingua::PT::Abbrev; | |||
8 | 9154 | ||||||
8 | 467 | ||||||
8 | |||||||
9 | require Exporter; | ||||||
10 | our @ISA = qw(Exporter); | ||||||
11 | |||||||
12 | 8 | 8 | 862 | use POSIX qw(locale_h); | |||
8 | 7227 | ||||||
8 | 71 | ||||||
13 | my $llang = setlocale(LC_CTYPE, "pt_PT"); | ||||||
14 | $llang = setlocale(LC_CTYPE, "pt_BR") unless $llang; | ||||||
15 | 8 | 8 | 6627 | use locale; | |||
8 | 828 | ||||||
8 | 49 | ||||||
16 | |||||||
17 | 8 | 8 | 7566 | use utf8; | |||
8 | 87 | ||||||
8 | 43 | ||||||
18 | |||||||
19 | |||||||
20 | =encoding UTF-8 | ||||||
21 | |||||||
22 | =head1 NAME | ||||||
23 | |||||||
24 | Lingua::PT::PLNbase - Perl extension for NLP of the Portuguese | ||||||
25 | |||||||
26 | =head1 SYNOPSIS | ||||||
27 | |||||||
28 | use Lingua::PT::PLNbase; | ||||||
29 | |||||||
30 | my @atomos = atomiza($texto); # tb chamada 'tokenize' | ||||||
31 | |||||||
32 | my $atomos_um_por_linha = tokeniza($texto); | ||||||
33 | my $atomos_separados_por_virgula = tokeniza({fs => ','}, $texto); | ||||||
34 | |||||||
35 | |||||||
36 | my @frases = frases($texto); | ||||||
37 | |||||||
38 | =head1 DESCRIPTION | ||||||
39 | |||||||
40 | Este módulo inclui funções básicas úteis ao processamento | ||||||
41 | computacional da língua, e em particular, da língua portuguesa. | ||||||
42 | |||||||
43 | =cut | ||||||
44 | |||||||
45 | |||||||
46 | |||||||
47 | our @EXPORT = qw( | ||||||
48 | atomiza frases separa_frases fsentences atomos | ||||||
49 | tokeniza has_accents remove_accents | ||||||
50 | xmlsentences sentences | ||||||
51 | cqptokens tokenize | ||||||
52 | ); | ||||||
53 | |||||||
54 | our $VERSION = '0.26'; | ||||||
55 | |||||||
56 | our $abrev; | ||||||
57 | |||||||
58 | our $terminador = qr{([.?!;]+[\»"'”’]?|<[pP]\b.*?>| |\n\n+|:\s+(?=[-\«"“‘][A-Z]))}; |
||||||
59 | |||||||
60 | our $protect = qr! | ||||||
61 | \#n\d+ | ||||||
62 | | \w+['’]\w+ | ||||||
63 | | \bn\.o # number | ||||||
64 | | [\w_.-]+ \@ [\w_.-]+\w # emails | ||||||
65 | | \w+\.?[ºª°]\.? # ordinals | ||||||
66 | | _sec[:+].*?_ # section marks from bookclean | ||||||
67 | | <[A-Za-z](?:\w|:)* # | ||||||
68 | (?:\s+ | ||||||
69 | [A-Za-z:0-9]+= # at='v' | ||||||
70 | (?: '[^']+' | ||||||
71 | | "[^"]+") | ||||||
72 | )* | ||||||
73 | \s*/?\s* | ||||||
74 | > # markup open XML SGML | ||||||
75 | | \s*[A-Za-z0-9:]+\s*> # markup close XML SGML | ||||||
76 | | \d+(?:\/\d+)+ # dates or similar 12/21/1 | ||||||
77 | | \d+(?:[.,]\d+)+%? # numbers | ||||||
78 | | \d+(?:\.[oa])+ # ordinals numbers 12.o | ||||||
79 | | \d+\:\d+(\:\d+)? # the time 12:12:2 | ||||||
80 | | (?:\&\w+\;) # entidades XML HTML | ||||||
81 | | ((https?|ftp|gopher)://|www)[\w_./~:-]+\w # urls | ||||||
82 | | \w+\.(?:com|org|net|pt) # simplified urls | ||||||
83 | | \w+(-\w+)+ # dá-lo-à | ||||||
84 | | \\\\unicode\{\d+\} # unicode... | ||||||
85 | | \w+\.(?:exe|html?|zip|jpg|gif|wav|mp3|png|t?gz|pl|xml) # filenames | ||||||
86 | !x; | ||||||
87 | |||||||
88 | |||||||
89 | our ($savit_n, %savit_p); | ||||||
90 | our %conf; | ||||||
91 | |||||||
92 | |||||||
93 | sub import { | ||||||
94 | 7 | 7 | 117 | my $class = shift; | |||
95 | 7 | 24 | our %conf = @_; | ||||
96 | 7 | 1848 | $class->export_to_level(1, undef, @EXPORT); | ||||
97 | |||||||
98 | 7 | 100 | 66 | 79 | if ($conf{abbrev} && -f $conf{abbrev}) { | ||
99 | 1 | 11 | $conf{ABBREV} = Lingua::PT::Abbrev->new($conf{abbrev}); | ||||
100 | } else { | ||||||
101 | 6 | 112 | $conf{ABBREV} = Lingua::PT::Abbrev->new(); | ||||
102 | } | ||||||
103 | |||||||
104 | 7 | 9630 | $abrev = $conf{ABBREV}->regexp(nodot=>1); | ||||
105 | } | ||||||
106 | |||||||
107 | |||||||
108 | sub _savit{ | ||||||
109 | 0 | 0 | my $a=shift; | ||||
110 | 0 | $savit_p{++$savit_n}=$a ; | |||||
111 | 0 | " __MARCA__$savit_n " | |||||
112 | } | ||||||
113 | |||||||
114 | sub _loadit{ | ||||||
115 | 0 | 0 | my $a = shift; | ||||
116 | 0 | $a =~ s/ ?__MARCA__(\d+) ?/$savit_p{$1}/g; | |||||
117 | 0 | $savit_n = 0; | |||||
118 | 0 | $a; | |||||
119 | } | ||||||
120 | |||||||
121 | |||||||
122 | |||||||
123 | sub _tokenizecommon{ | ||||||
124 | 0 | 0 | my $conf = { keep_quotes => 0 }; | ||||
125 | 0 | 0 | if (ref($_[0]) eq "HASH") { | ||||
126 | 0 | my $c = shift; | |||||
127 | 0 | $conf = {%$conf, %$c}; | |||||
128 | } | ||||||
129 | |||||||
130 | 0 | my $text = shift; | |||||
131 | |||||||
132 | 0 | for ($text) { | |||||
133 | 0 | s/<\?xml.*?\?>//s; | |||||
134 | |||||||
135 | 0 | 0 | if ($conf->{keep_quotes}) { | ||||
136 | 0 | s#\"# \" #g; | |||||
137 | } else { | ||||||
138 | 0 | s/^\"/\« /g; | |||||
139 | 0 | s/ \"/ \« /g; | |||||
140 | 0 | s/\"([ .?!:;,])/ \» $1/g; | |||||
141 | 0 | s/\"$/ \»/g; | |||||
142 | } | ||||||
143 | |||||||
144 | 0 | s!(\w)(['’](s|ld|nt|ll|m|t|re))\b!"$1 " . _savit($2)!ge; # I 'm we 're can 't | |||||
0 | |||||||
145 | 0 | s!([[:alpha:]]+')(\w)! _savit($1) . " $2"!ge; | |||||
0 | |||||||
146 | |||||||
147 | 0 | 0 | if ($conf->{keep_quotes}) { | ||||
148 | 0 | s#\'# \' #g; | |||||
149 | } else { | ||||||
150 | 0 | s/^\`/\« /g; | |||||
151 | 0 | s/ \`/ \« /g; | |||||
152 | |||||||
153 | 0 | s/^\'/\« /g; | |||||
154 | 0 | s/ \'/ \« /g; | |||||
155 | 0 | s/\'([ .?!:;,])/ \» $1/g; | |||||
156 | 0 | s/\'$/ \»/g; | |||||
157 | } | ||||||
158 | |||||||
159 | 0 | s!($protect)! _savit($1)!xge; | |||||
0 | |||||||
160 | 0 | s!\b((([A-Z])\.)+)!_savit($1)!gie; | |||||
0 | |||||||
161 | |||||||
162 | 0 | s!([\»\]])!$1 !g; # » | ] | |||||
163 | 0 | s!([\«\[])! $1!g; | |||||
164 | |||||||
165 | 0 | s/(\s*\b\s*|\s+)/\n/g; | |||||
166 | |||||||
167 | # s/(.)\n-\n/$1-/g; | ||||||
168 | 0 | s/\n+/\n/g; | |||||
169 | 0 | s/\n(\.?[ºª°])\b/$1/g; | |||||
170 | |||||||
171 | |||||||
172 | 0 | s#\n($abrev)\n\.\n#\n$1\.\n#ig; | |||||
173 | |||||||
174 | 0 | s#([\]\)])([.,;:!?])#$1\n$2#g; | |||||
175 | |||||||
176 | 0 | s/\n*\n; | |||||
177 | 0 | $_ = _loadit($_); | |||||
178 | 0 | s/(\s*\n)+$/\n/; | |||||
179 | 0 | s/^(\s*\n)+//; | |||||
180 | } | ||||||
181 | $text | ||||||
182 | 0 | } | |||||
183 | |||||||
184 | =head2 Atomizadores | ||||||
185 | |||||||
186 | Este módulo inclui um método configurável para a atomização de corpus | ||||||
187 | na língua portuguesa. No entanto, é possível que possa ser usado para | ||||||
188 | outras línguas (especialmente inglês e francês. | ||||||
189 | |||||||
190 | A forma simples de uso do atomizador é usando directamente a função | ||||||
191 | C |
||||||
192 | o uso da função C |
||||||
193 | |||||||
194 | As funções disponíveis: | ||||||
195 | |||||||
196 | =over 4 | ||||||
197 | |||||||
198 | =item atomos | ||||||
199 | |||||||
200 | =item atomiza | ||||||
201 | |||||||
202 | =item tokenize | ||||||
203 | |||||||
204 | Usa um algorítmo desenvolvido no Projecto Natura. | ||||||
205 | |||||||
206 | Para que as aspas não sejam convertidas em I | ||||||
207 | aspa>, usar a opção de configuração C |
||||||
208 | |||||||
209 | Retorna texto tokenizado, um por linha (a nao ser que o 'record | ||||||
210 | separator' (rs) seja redefenido). Em ambiente lista, retorna a lista | ||||||
211 | dos átomos. | ||||||
212 | |||||||
213 | my @atomos = atomiza($texto); # tb chamada 'tokenize' | ||||||
214 | |||||||
215 | my $atomos_um_por_linha = tokeniza($texto); | ||||||
216 | my $atomos_separados_por_virgula = tokeniza({fs => ','}, $texto); | ||||||
217 | |||||||
218 | |||||||
219 | =item tokeniza | ||||||
220 | |||||||
221 | Usa um algoritmo desenvolvido no Pólo de Oslo da Linguateca. Retorna | ||||||
222 | um átomo por linha em contexto escalar, e uma lista de átomos em | ||||||
223 | contexto de lista. | ||||||
224 | |||||||
225 | =item cqptokens | ||||||
226 | |||||||
227 | Um átomo por linha de acordo com notação CWB. Pode ser alterado o | ||||||
228 | separador de frases (ou de registo) usando a opção 'irs': | ||||||
229 | |||||||
230 | cqptokens( { irs => "\n\n" }, "file" ); | ||||||
231 | |||||||
232 | outras opções: | ||||||
233 | |||||||
234 | cqptokens( { enc => ":utf8"}, "file" ); # enc => charset | ||||||
235 | # outenc => charset | ||||||
236 | |||||||
237 | =back | ||||||
238 | |||||||
239 | =cut | ||||||
240 | |||||||
241 | 0 | 0 | 1 | sub atomos { tokenize(@_) } | |||
242 | 0 | 0 | 1 | sub atomiza { tokenize(@_) } | |||
243 | |||||||
244 | sub tokenize{ | ||||||
245 | 0 | 0 | 1 | my $conf = { rs => "\n" }; | |||
246 | 0 | my $result = ""; | |||||
247 | 0 | my $text = shift; | |||||
248 | |||||||
249 | 0 | 0 | if (ref($text) eq "HASH") { | ||||
250 | 0 | $conf = { %$conf, %$text }; | |||||
251 | 0 | $text = shift; | |||||
252 | } | ||||||
253 | |||||||
254 | 0 | $result = _tokenizecommon($conf, $text); | |||||
255 | 0 | $result =~ s/\n$//g; | |||||
256 | |||||||
257 | 0 | 0 | if (wantarray) { | ||||
258 | 0 | return split /\n+/, $result | |||||
259 | } else { | ||||||
260 | 0 | 0 | $result =~ s/\n/$conf->{rs}/g unless $conf->{rs} eq "\n"; | ||||
261 | 0 | return $result; | |||||
262 | } | ||||||
263 | } | ||||||
264 | |||||||
265 | sub cqptokens{ ## | ||||||
266 | 0 | 0 | 1 | my %opt = ( irs => ">"); # irs => INPUT RECORD SEPARATOR; | |||
267 | # enc => charset | ||||||
268 | # outenc => charset | ||||||
269 | 0 | 0 | if(ref($_[0]) eq "HASH"){ %opt = (%opt , %{shift(@_)});} | ||||
0 | |||||||
0 | |||||||
270 | 0 | 0 | my $file = shift || "-"; | ||||
271 | |||||||
272 | 0 | local $/ = $opt{irs}; | |||||
273 | 0 | my %tag=(); | |||||
274 | 0 | my ($a,$b); | |||||
275 | 0 | open(F,"$file"); | |||||
276 | 0 | 0 | binmode(F,$opt{enc}) if $opt{enc}; | ||||
277 | 0 | 0 | binmode(STDOUT,$opt{outenc}) if $opt{outenc}; | ||||
278 | 0 | while( |
|||||
279 | 0 | 0 | if(/<(\w+)(.*?)>/){ | ||||
280 | 0 | ($a, $b) = ($1,$2); | |||||
281 | 0 | 0 | if ($b =~ /=/ ) { $tag{'v'}{$a}++ } | ||||
0 | |||||||
282 | 0 | else { $tag{'s'}{$a}++ } | |||||
283 | } | ||||||
284 | 0 | print _tokenizecommon({},$_) | |||||
285 | } | ||||||
286 | 0 | return \%tag | |||||
287 | } | ||||||
288 | |||||||
289 | |||||||
290 | |||||||
291 | =head2 Segmentadores | ||||||
292 | |||||||
293 | Este módulo é uma extensão Perl para a segmentação de textos em | ||||||
294 | linguagem natural. O objectivo principal será a possibilidade de | ||||||
295 | segmentação a vários níveis, no entanto esta primeira versão permite | ||||||
296 | apenas a separação em frases (fraseação) usando uma de duas variantes: | ||||||
297 | |||||||
298 | =over 4 | ||||||
299 | |||||||
300 | =item C |
||||||
301 | |||||||
302 | =item C |
||||||
303 | |||||||
304 | @frases = frases($texto); | ||||||
305 | |||||||
306 | Esta é a implementação do Projecto Natura, que retorna uma lista de | ||||||
307 | frases. | ||||||
308 | |||||||
309 | =item C |
||||||
310 | |||||||
311 | $frases = separa_frases($texto); | ||||||
312 | |||||||
313 | Esta é a implementação da Linguateca, que retorna um texto com uma | ||||||
314 | frase por linha. | ||||||
315 | |||||||
316 | =item C |
||||||
317 | |||||||
318 | Utiliza o método C |
||||||
319 | as frases são ladeadas por ' |
||||||
320 | substituído usando o parametro opcional C |
||||||
321 | |||||||
322 | xmlsentences({st=> "tag"}, text) | ||||||
323 | |||||||
324 | =back | ||||||
325 | |||||||
326 | =cut | ||||||
327 | |||||||
328 | sub xmlsentences { | ||||||
329 | 0 | 0 | 1 | my %opt = (st => "s") ; | |||
330 | 0 | 0 | if (ref($_[0]) eq "HASH"){ %opt = (%opt , %{shift(@_)});} | ||||
0 | |||||||
0 | |||||||
331 | 0 | my $par=shift; | |||||
332 | 0 | join("\n",map {"<$opt{st}>$_$opt{st}>"} (sentences($par))); | |||||
0 | |||||||
333 | } | ||||||
334 | |||||||
335 | |||||||
336 | |||||||
337 | 0 | 0 | 1 | sub frases { sentences(@_) } | |||
338 | sub sentences{ | ||||||
339 | 0 | 0 | 1 | my @r; | |||
340 | 0 | my $MARCA = "\0x01"; | |||||
341 | 0 | my $par = shift; | |||||
342 | 0 | for ($par) { | |||||
343 | 0 | s!($protect)! _savit($1)!xge; | |||||
0 | |||||||
344 | 0 | s!\b(($abrev)\.)! _savit($1)!ige; | |||||
0 | |||||||
345 | 0 | s!\b(([A-Z])\.)! _savit($1)!gie; # este à parte para não apanhar minúlculas (s///i) | |||||
0 | |||||||
346 | 0 | s!($terminador)!$1$MARCA!g; | |||||
347 | 0 | $_ = _loadit($_); | |||||
348 | 0 | @r = split(/$MARCA/,$_); | |||||
349 | } | ||||||
350 | 0 | 0 | 0 | if (@r && $r[-1] =~ /^\s*$/s) { | |||
351 | 0 | pop(@r) | |||||
352 | } | ||||||
353 | 0 | return map { _trim($_) } @r; | |||||
0 | |||||||
354 | } | ||||||
355 | |||||||
356 | sub _trim { | ||||||
357 | 0 | 0 | my $x = shift; | ||||
358 | 0 | $x =~ s/^[\n\r\s]+//; | |||||
359 | 0 | $x =~ s/[\n\r\s]+$//; | |||||
360 | 0 | return $x; | |||||
361 | } | ||||||
362 | |||||||
363 | |||||||
364 | =head2 Segmentação a vários níveis | ||||||
365 | |||||||
366 | =over 4 | ||||||
367 | |||||||
368 | =item fsentences | ||||||
369 | |||||||
370 | A função C |
||||||
371 | vários níveis: por ficheiro, por parágrafo ou por frase. O output pode | ||||||
372 | ser realizado em vários formatos e obtendo, ou não, numeração de | ||||||
373 | segmentos. | ||||||
374 | |||||||
375 | Esta função é invocada com uma referência para um hash de configuração | ||||||
376 | e uma lista de ficheiros a processar (no caso de a lista ser vazia, | ||||||
377 | irá usar o C |
||||||
378 | |||||||
379 | O resultado do processamento é enviado para o C |
||||||
380 | a chave C | ||||||
381 | o seu valor será usado como ficheiro de resultado. | ||||||
382 | |||||||
383 | A chave C |
||||||
384 | omissão, é usada uma linha em branco. | ||||||
385 | |||||||
386 | A chave C |
||||||
387 | resultado. De momento, a única política disponível é a C |
||||||
388 | |||||||
389 | As chaves C |
||||||
390 | na política XML, para etiquetar frases, parágrafos e textos | ||||||
391 | (ficheiros), respectivamente. Por omissão, as etiquetas usadas são | ||||||
392 | C e C |
||||||
393 | |||||||
394 | É possível numerar as etiquetas, definindo as chaves C |
||||||
395 | C |
||||||
396 | |||||||
397 | =over 4 | ||||||
398 | |||||||
399 | =item '0' | ||||||
400 | |||||||
401 | Nenhuma numeração. | ||||||
402 | |||||||
403 | =item 'f' | ||||||
404 | |||||||
405 | Só pode ser usado com o C |
||||||
406 | delimitam ficheiros usará o nome do ficheiro como identificador. | ||||||
407 | |||||||
408 | =item '1' | ||||||
409 | |||||||
410 | Numeração a um nível. Cada etiqueta terá um contador diferente. | ||||||
411 | |||||||
412 | =item '2' | ||||||
413 | |||||||
414 | Só pode ser usado com o C |
||||||
415 | dois níveis (N.N). | ||||||
416 | |||||||
417 | =item '3' | ||||||
418 | |||||||
419 | Só pode ser usado com o C |
||||||
420 | |||||||
421 | =back | ||||||
422 | |||||||
423 | =back | ||||||
424 | |||||||
425 | |||||||
426 | nomes das etiquetas (s => 's', p=>'p', t=>'text') | ||||||
427 | |||||||
428 | t: 0 - nenhuma | ||||||
429 | 1 - numeracao | ||||||
430 | f - ficheiro [DEFAULT] | ||||||
431 | |||||||
432 | p: 0 - nenhuma | ||||||
433 | 1 - numeracao 1 nivel [DEFAULT] | ||||||
434 | 2 - numercao 2 niveis (N.N) | ||||||
435 | |||||||
436 | s: 0 - nenhuma | ||||||
437 | 1 - numeração 1 nível [DEFAULT] | ||||||
438 | 2 - numeração 2 níveis (N.N) | ||||||
439 | 3 - numeração 3 níveis (N.N.N) | ||||||
440 | |||||||
441 | =cut | ||||||
442 | |||||||
443 | sub fsentences { | ||||||
444 | 0 | 0 | 1 | my %opts = ( | |||
445 | o_format => 'XML', | ||||||
446 | s_tag => 's', | ||||||
447 | s_num => '1', | ||||||
448 | s_last => '', | ||||||
449 | |||||||
450 | p_tag => 'p', | ||||||
451 | p_num => '1', | ||||||
452 | p_last => '', | ||||||
453 | |||||||
454 | t_tag => 'text', | ||||||
455 | t_num => 'f', | ||||||
456 | t_last => '', | ||||||
457 | |||||||
458 | tokenize => 0, | ||||||
459 | |||||||
460 | output => \*STDOUT, | ||||||
461 | input_p_sep => '', | ||||||
462 | ); | ||||||
463 | |||||||
464 | 0 | 0 | %opts = (%opts, %{shift()}) if ref($_[0]) eq "HASH"; | ||||
0 | |||||||
465 | |||||||
466 | |||||||
467 | 0 | my @files = @_; | |||||
468 | 0 | 0 | @files = (\*STDIN) unless @files; | ||||
469 | |||||||
470 | 0 | my $oldselect; | |||||
471 | 0 | 0 | if (!ref($opts{output})) { | ||||
472 | 0 | 0 | open OUT, ">$opts{output}" or die("Cannot open file for writting: $!\n"); | ||||
473 | 0 | $oldselect = select OUT; | |||||
474 | } | ||||||
475 | |||||||
476 | 0 | for my $file (@files) { | |||||
477 | 0 | my $fh; | |||||
478 | 0 | 0 | if (ref($file)) { | ||||
479 | 0 | $fh = $file; | |||||
480 | } else { | ||||||
481 | 0 | 0 | open $fh, $file or die("Cannot open file $file:$!\n"); | ||||
482 | 0 | print _open_t_tag(\%opts, $file); | |||||
483 | } | ||||||
484 | |||||||
485 | 0 | my $par; | |||||
486 | 0 | local $/ = $opts{input_p_sep}; | |||||
487 | 0 | while ($par = <$fh>) { | |||||
488 | 0 | print _open_p_tag(\%opts); | |||||
489 | |||||||
490 | 0 | chomp($par); | |||||
491 | |||||||
492 | 0 | for my $s (sentences($par)) { | |||||
493 | 0 | print _open_s_tag(\%opts), _clean(\%opts,$s), _close_s_tag(\%opts); | |||||
494 | } | ||||||
495 | |||||||
496 | 0 | print _close_p_tag(\%opts); | |||||
497 | } | ||||||
498 | |||||||
499 | |||||||
500 | 0 | 0 | unless (ref($file)) { | ||||
501 | 0 | print _close_t_tag(\%opts); | |||||
502 | 0 | close $fh | |||||
503 | } | ||||||
504 | |||||||
505 | } | ||||||
506 | |||||||
507 | 0 | 0 | if (!ref($opts{output})) { | ||||
508 | 0 | close OUT; | |||||
509 | 0 | select $oldselect; | |||||
510 | } | ||||||
511 | |||||||
512 | } | ||||||
513 | |||||||
514 | sub _clean { | ||||||
515 | 0 | 0 | my $opts = shift; | ||||
516 | 0 | my $str = shift; | |||||
517 | |||||||
518 | 0 | 0 | if ($opts->{tokenize}) { | ||||
519 | 0 | 0 | if ($opts->{tokenize} eq "cqp") { | ||||
520 | 0 | $str = "\n".join("\n", atomiza($str))."\n" | |||||
521 | } else { | ||||||
522 | 0 | $str = join(" ", atomiza($str)) | |||||
523 | } | ||||||
524 | } else { | ||||||
525 | 0 | $str =~ s/\s+/ /g; | |||||
526 | } | ||||||
527 | 0 | $str =~ s/&/&/g; | |||||
528 | 0 | $str =~ s/>/>/g; | |||||
529 | 0 | $str =~ s/</g; | |||||
530 | 0 | return $str; | |||||
531 | } | ||||||
532 | |||||||
533 | sub _open_t_tag { | ||||||
534 | 0 | 0 | my $opts = shift; | ||||
535 | 0 | 0 | my $file = shift || ""; | ||||
536 | 0 | 0 | 0 | if ($opts->{o_format} eq "XML" && | |||
537 | $opts->{t_tag}) { | ||||||
538 | 0 | 0 | if ($opts->{t_num} eq 0) { | ||||
0 | |||||||
539 | 0 | return "<$opts->{t_tag}>\n"; | |||||
540 | } elsif ($opts->{t_num} eq 'f') { | ||||||
541 | 0 | $opts->{t_last} = $file; | |||||
542 | 0 | $opts->{p_last} = 0; | |||||
543 | 0 | $opts->{s_last} = 0; | |||||
544 | 0 | return "<$opts->{t_tag} file=\"$file\">\n"; | |||||
545 | } else { | ||||||
546 | ## t_num = 1 :-) | ||||||
547 | 0 | ++$opts->{t_last}; | |||||
548 | 0 | $opts->{p_last} = 0; | |||||
549 | 0 | $opts->{s_last} = 0; | |||||
550 | 0 | return "<$opts->{t_tag} id=\"$opts->{t_last}\">\n"; | |||||
551 | } | ||||||
552 | } | ||||||
553 | 0 | 0 | return "" if ($opts->{o_format} eq "NATools"); | ||||
554 | } | ||||||
555 | |||||||
556 | sub _close_t_tag { | ||||||
557 | 0 | 0 | my $opts = shift; | ||||
558 | 0 | 0 | my $file = shift || ""; | ||||
559 | 0 | 0 | 0 | if ($opts->{o_format} eq "XML" && | |||
560 | $opts->{t_tag}) { | ||||||
561 | 0 | return "$opts->{t_tag}>\n"; | |||||
562 | } | ||||||
563 | 0 | 0 | return "" if ($opts->{o_format} eq "NATools"); | ||||
564 | } | ||||||
565 | |||||||
566 | sub _open_p_tag { | ||||||
567 | 0 | 0 | my $opts = shift; | ||||
568 | |||||||
569 | 0 | 0 | 0 | if ($opts->{o_format} eq "XML" && | |||
570 | $opts->{p_tag}) { | ||||||
571 | 0 | 0 | if ($opts->{p_num} == 0) { | ||||
0 | |||||||
572 | 0 | return "<$opts->{p_tag}>\n"; | |||||
573 | } elsif ($opts->{p_num} == 1) { | ||||||
574 | 0 | ++$opts->{p_last}; | |||||
575 | 0 | $opts->{s_last} = 0; | |||||
576 | 0 | return "<$opts->{p_tag} id=\"$opts->{p_last}\">\n"; | |||||
577 | } else { | ||||||
578 | ## p_num = 2 | ||||||
579 | 0 | ++$opts->{p_last}; | |||||
580 | 0 | $opts->{s_last} = 0; | |||||
581 | 0 | return "<$opts->{p_tag} id=\"$opts->{t_last}.$opts->{p_last}\">\n"; | |||||
582 | } | ||||||
583 | } | ||||||
584 | 0 | 0 | return "" if ($opts->{o_format} eq "NATools"); | ||||
585 | } | ||||||
586 | |||||||
587 | sub _close_p_tag { | ||||||
588 | 0 | 0 | my $opts = shift; | ||||
589 | 0 | 0 | my $file = shift || ""; | ||||
590 | 0 | 0 | 0 | if ($opts->{o_format} eq "XML" && | |||
591 | $opts->{p_tag}) { | ||||||
592 | 0 | return "$opts->{p_tag}>\n"; | |||||
593 | } | ||||||
594 | 0 | 0 | return "" if ($opts->{o_format} eq "NATools"); | ||||
595 | } | ||||||
596 | |||||||
597 | |||||||
598 | sub _open_s_tag { | ||||||
599 | 0 | 0 | my $opts = shift; | ||||
600 | |||||||
601 | 0 | 0 | 0 | if ($opts->{o_format} eq "XML" && | |||
602 | $opts->{s_tag}) { | ||||||
603 | 0 | 0 | if ($opts->{s_num} == 0) { | ||||
0 | |||||||
0 | |||||||
604 | 0 | return "<$opts->{s_tag}>"; | |||||
605 | } elsif ($opts->{s_num} == 1) { | ||||||
606 | 0 | ++$opts->{s_last}; | |||||
607 | 0 | return "<$opts->{s_tag} id=\"$opts->{s_last}\">"; | |||||
608 | |||||||
609 | } elsif ($opts->{s_num} == 2) { | ||||||
610 | 0 | ++$opts->{s_last}; | |||||
611 | 0 | return "<$opts->{s_tag} id=\"$opts->{p_last}.$opts->{s_last}\">"; | |||||
612 | |||||||
613 | } else { | ||||||
614 | ## p_num = 3 | ||||||
615 | 0 | ++$opts->{s_last}; | |||||
616 | 0 | return "<$opts->{s_tag} id=\"$opts->{t_last}.$opts->{p_last}.$opts->{s_last}\">"; | |||||
617 | } | ||||||
618 | } | ||||||
619 | 0 | 0 | return "" if ($opts->{o_format} eq "NATools"); | ||||
620 | } | ||||||
621 | |||||||
622 | sub _close_s_tag { | ||||||
623 | 0 | 0 | my $opts = shift; | ||||
624 | 0 | 0 | my $file = shift || ""; | ||||
625 | 0 | 0 | 0 | if ($opts->{o_format} eq "XML" && | |||
626 | $opts->{s_tag}) { | ||||||
627 | 0 | return "$opts->{s_tag}>\n"; | |||||
628 | } | ||||||
629 | 0 | 0 | return "\n\$\n" if ($opts->{o_format} eq "NATools"); | ||||
630 | } | ||||||
631 | |||||||
632 | |||||||
633 | |||||||
634 | |||||||
635 | |||||||
636 | =head2 Acentuação | ||||||
637 | |||||||
638 | =over 4 | ||||||
639 | |||||||
640 | =item remove_accents | ||||||
641 | |||||||
642 | Esta função remove a acentuação do texto passado como parâmetro | ||||||
643 | |||||||
644 | =item has_accents | ||||||
645 | |||||||
646 | Esta função verifica se o texto passado como parâmetro tem caracteres acentuados | ||||||
647 | |||||||
648 | =back | ||||||
649 | |||||||
650 | =cut | ||||||
651 | |||||||
652 | sub has_accents { | ||||||
653 | 0 | 0 | 1 | my $word = shift; | |||
654 | 0 | 0 | if ($word =~ m![çáéíóúàèìòùãõâêîôûäëïöüñ]!i) { | ||||
655 | 0 | return 1 | |||||
656 | } else { | ||||||
657 | 0 | return 0 | |||||
658 | } | ||||||
659 | } | ||||||
660 | |||||||
661 | sub remove_accents { | ||||||
662 | 0 | 0 | 1 | my $word = shift; | |||
663 | 8 | 8 | 39260 | $word =~ tr/çáéíóúàèìòùãõâêîôûäëïöüñ/caeiouaeiouaoaeiouaeioun/; | |||
8 | 23 | ||||||
8 | 115 | ||||||
0 | |||||||
664 | 0 | $word =~ tr/ÇÁÉÍÓÚÀÈÌÒÙÃÕÂÊÎÔÛÄËÏÖÜÑ/CAEIOUAEIOUAOAEIOUAEIOUN/; | |||||
665 | 0 | return $word; | |||||
666 | } | ||||||
667 | |||||||
668 | |||||||
669 | |||||||
670 | |||||||
671 | |||||||
672 | ### ---------- OSLO -------- | ||||||
673 | |||||||
674 | sub tokeniza { | ||||||
675 | 0 | 0 | 1 | my $par = shift; | |||
676 | |||||||
677 | 0 | for ($par) { | |||||
678 | 0 | s/([!?]+)/ $1/g; | |||||
679 | 0 | s/([.,;\»´])/ $1/g; | |||||
680 | |||||||
681 | # separa os dois pontos só se não entre números 9:30... | ||||||
682 | 0 | s/:([^0-9])/ :$1/g; | |||||
683 | |||||||
684 | # separa os dois pontos só se não entre números e não for http:/... | ||||||
685 | 0 | s/([^0-9]):([^\/])/$1 :$2/g; | |||||
686 | |||||||
687 | # was s/([«`])/$1 /g; -- mas tava a dar problemas com o emacs :| | ||||||
688 | 0 | s!([`])!$1 !g; | |||||
689 | |||||||
690 | # só separa o parêntesis esquerdo quando não engloba números ou asterisco | ||||||
691 | 0 | s/\(([^1-9*])/\( $1/g; | |||||
692 | |||||||
693 | # só separa o parêntesis direito quando não engloba números ou asterisco ou percentagem | ||||||
694 | 0 | s/([^0-9*%])\)/$1 \)/g; | |||||
695 | |||||||
696 | # desfaz a separação dos parênteses para B) | ||||||
697 | 0 | s/> *([A-Za-z]) \)/> $1\)/g; | |||||
698 | |||||||
699 | # desfaz a separação dos parênteses para (a) | ||||||
700 | 0 | s/> *\( ([a-z]) \)/> \($1\)/g; | |||||
701 | |||||||
702 | # separação dos parênteses para ( A4 ) | ||||||
703 | 0 | s/(\( +[A-Z]+[0-9]+)\)/ $1 \)/g; | |||||
704 | |||||||
705 | # separa o parêntesis recto esquerdo desde que não [.. | ||||||
706 | 0 | s/\[([^.§])/[ $1/g; | |||||
707 | |||||||
708 | # separa o parêntesis recto direito desde que não ..] | ||||||
709 | 0 | s/([^.§])\]/$1 ]/g; | |||||
710 | |||||||
711 | # separa as reticências só se não dentro de [...] | ||||||
712 | 0 | s/([^[])§/$1 §/g; | |||||
713 | |||||||
714 | # desfaz a separação dos http: | ||||||
715 | 0 | s/http :/http:/g; | |||||
716 | |||||||
717 | # separa as aspas anteriores | ||||||
718 | 0 | s/ \"/ \« /g; | |||||
719 | |||||||
720 | # separa as aspas anteriores mesmo no inicio | ||||||
721 | 0 | s/^\"/ \« /g; | |||||
722 | |||||||
723 | # separa as aspas posteriores | ||||||
724 | 0 | s/\" / \» /g; | |||||
725 | |||||||
726 | # separa as aspas posteriores mesmo no fim | ||||||
727 | 0 | s/\"$/ \»/g; | |||||
728 | |||||||
729 | # trata dos apóstrofes | ||||||
730 | # trata do apóstrofe: só separa se for pelica | ||||||
731 | 0 | s/([^dDlL])\'([\s\',:.?!])/$1 \'$2/g; | |||||
732 | # trata do apóstrofe: só separa se for pelica | ||||||
733 | 0 | s/(\S[dDlL])\'([\s\',:.?!])/$1 \'$2/g; | |||||
734 | # separa d' do resto da palavra "d'amor"... "dest'época" | ||||||
735 | 0 | s/([A-ZÊÁÉÍÓÚÀÇÔÕÃÂa-zôõçáéíóúâêàã])\'([A-ZÊÁÉÍÓÚÀÇÔÕÃÂa-zôõçáéíóúâêàã])/$1\' $2/; | |||||
736 | |||||||
737 | #Para repor PME's | ||||||
738 | 0 | s/(\s[A-Z]+)\' s([\s,:.?!])/$1\'s$2/g; | |||||
739 | |||||||
740 | # isto é para o caso dos apóstrofos não terem sido tratados pelo COMPARA | ||||||
741 | # separa um apóstrofe final usado como inicial | ||||||
742 | 0 | s/ '([A-Za-zÁÓÚÉÊÀÂÍ])/ ' $1/g; | |||||
743 | # separa um apóstrofe final usado como inicial | ||||||
744 | 0 | s/^'([A-Za-zÁÓÚÉÊÀÂÍ])/' $1/g; | |||||
745 | |||||||
746 | # isto é para o caso dos apóstrofes (plicas) serem os do COMPARA | ||||||
747 | 0 | s/\`([^ ])/\` $1/g; | |||||
748 | 0 | s/([^ ])´/$1 ´/g; | |||||
749 | |||||||
750 | # trata dos (1) ou 1) | ||||||
751 | # separa casos como Rocha(1) para Rocha (1) | ||||||
752 | 0 | s/([a-záéãó])\(([0-9])/$1 \($2/g; | |||||
753 | # separa casos como dupla finalidade:1) | ||||||
754 | 0 | s/:([0-9]\))/ : $1/g; | |||||
755 | |||||||
756 | # trata dos hífenes | ||||||
757 | # separa casos como (Itália)-Juventus para Itália) - | ||||||
758 | 0 | s/\)\-([A-Z])/\) - $1/g; | |||||
759 | # separa casos como 1-universidade | ||||||
760 | 0 | s/([0-9]\-)([^0-9\s])/$1 $2/g; | |||||
761 | } | ||||||
762 | |||||||
763 | #trata das barras | ||||||
764 | #se houver palavras que nao sao todas em maiusculas, separa | ||||||
765 | 0 | my @barras = ($par=~m%(?:[a-z]+/)+(?:[A-Za-z][a-z]*)%g); | |||||
766 | 0 | my $exp_antiga; | |||||
767 | 0 | foreach my $exp_com_barras (@barras) { | |||||
768 | 0 | 0 | 0 | if (($exp_com_barras !~ /[a-z]+a\/o$/) and # Ambicioso/a | |||
0 | |||||||
769 | ($exp_com_barras !~ /[a-z]+o\/a$/) and # cozinheira/o | ||||||
770 | ($exp_com_barras !~ /[a-z]+r\/a$/)) { # desenhador/a | ||||||
771 | 0 | $exp_antiga=$exp_com_barras; | |||||
772 | 0 | $exp_com_barras=~s#/# / #g; | |||||
773 | 0 | $par=~s/$exp_antiga/$exp_com_barras/g; | |||||
774 | } | ||||||
775 | } | ||||||
776 | |||||||
777 | 0 | for ($par) { | |||||
778 | 0 | s# e / ou # e/ou #g; | |||||
779 | 0 | s#([Kk])m / h#$1m/h#g; | |||||
780 | 0 | s# mg / kg# mg/kg#g; | |||||
781 | 0 | s#r / c#r/c#g; | |||||
782 | 0 | s#m / f#m/f#g; | |||||
783 | 0 | s#f / m#f/m#g; | |||||
784 | } | ||||||
785 | |||||||
786 | |||||||
787 | 0 | 0 | if (wantarray) { | ||||
788 | 0 | return split /\s+/, $par | |||||
789 | } else { | ||||||
790 | 0 | $par =~ s/\s+/\n/g; | |||||
791 | 0 | return $par | |||||
792 | } | ||||||
793 | } | ||||||
794 | |||||||
795 | |||||||
796 | |||||||
797 | sub tratar_pontuacao_interna { | ||||||
798 | 0 | 0 | 1 | my $par = shift; | |||
799 | |||||||
800 | # print "Estou no pontuação interna... $par\n"; | ||||||
801 | |||||||
802 | 0 | for ($par) { | |||||
803 | # proteger o § | ||||||
804 | 0 | s/§/§§/g; | |||||
805 | |||||||
806 | # tratar das reticências | ||||||
807 | 0 | s/\.\.\.+/§/g; | |||||
808 | |||||||
809 | 0 | s/\+/\+\+/g; | |||||
810 | |||||||
811 | # tratar de iniciais seguidas por ponto, eventualmente com | ||||||
812 | # parênteses, no fim de uma frase | ||||||
813 | 0 | s/([A-Z])\. ([A-Z])\.(\s*[])]*\s*)$/$1+ $2+$3 /g; | |||||
814 | |||||||
815 | # iniciais com espaço no meio... | ||||||
816 | 0 | s/ a\. C\./ a+C+/g; | |||||
817 | 0 | s/ d\. C\./ d+C+/g; | |||||
818 | |||||||
819 | # tratar dos pontos nas abreviaturas | ||||||
820 | 0 | s/\.º/º+/g; | |||||
821 | 0 | s/º\./+º/g; | |||||
822 | 0 | s/\.ª/+ª/g; | |||||
823 | 0 | s/ª\./ª+/g; | |||||
824 | |||||||
825 | #só mudar se não for ambíguo com ponto final | ||||||
826 | 0 | s/º\. +([^A-ZÀÁÉÍÓÚÂÊ\«])/º+ $1/g; | |||||
827 | |||||||
828 | # formas de tratamento | ||||||
829 | 0 | s/Ex\./Ex+/g; # Ex. | |||||
830 | 0 | s/ ex\./ ex+/g; # ex. | |||||
831 | 0 | s/Exa(s*)\./Exa$1+/g; # Exa., Exas. | |||||
832 | 0 | s/ exa(s*)\./ exa$1+/g; # exa., exas | |||||
833 | 0 | s/Pe\./Pe+/g; | |||||
834 | 0 | s/Dr(a*)\./Dr$1+/g; # Dr., Dra. | |||||
835 | 0 | s/ dr(a*)\./ dr$1+/g; # dr., dra. | |||||
836 | 0 | s/ drs\./ drs+/g; # drs. | |||||
837 | 0 | s/Eng(a*)\./Eng$1+/g; # Eng., Enga. | |||||
838 | 0 | s/ eng(a*)\./ eng$1+/g; # eng., enga. | |||||
839 | 0 | s/([Ss])r(t*)a\./$1r$2a+/g; # Sra., sra., Srta., srta. | |||||
840 | 0 | s/([Ss])r(s*)\./$1r$2+/g; # Sr., sr., Srs., srs. | |||||
841 | 0 | s/ arq\./ arq+/g; # arq. | |||||
842 | 0 | s/Prof(s*)\./Prof$1+/g; # Prof., Profs. | |||||
843 | 0 | s/Profa(s*)\./Profa$1+/g; # Profa., Profas. | |||||
844 | 0 | s/ prof(s*)\./ prof$1+/g; # prof., profs. | |||||
845 | 0 | s/ profa(s*)\./ profa$1+/g; # profa., profas. | |||||
846 | 0 | s/\. Sen\./+ Sen+/g; # senador (vem sempre depois de Av. ou R. ...) | |||||
847 | 0 | s/ua Sen\./ua Sen+/g; # senador (depois [Rr]ua ...) | |||||
848 | 0 | s/Cel\./Cel+/g; # coronel | |||||
849 | 0 | s/ d\. / d+ /g; # d. Luciano | |||||
850 | |||||||
851 | # partes de nomes (pospostos) | ||||||
852 | 0 | s/ ([lL])da\./ $1da+/g; # limitada | |||||
853 | 0 | s/ cia\./ cia+/g; # companhia | |||||
854 | 0 | s/Cia\./Cia+/g; # companhia | |||||
855 | 0 | s/Jr\./Jr+/g; | |||||
856 | |||||||
857 | # moradas | ||||||
858 | 0 | s/Av\./Av+/g; | |||||
859 | 0 | s/ av\./ av+/g; | |||||
860 | 0 | s/Est(r*)\./Est$1+/g; | |||||
861 | 0 | s/Lg(o*)\./Lg$1+/g; | |||||
862 | 0 | s/ lg(o*)\./ lg$1+/g; | |||||
863 | 0 | s/T(ra)*v\./T$1v+/g; # Trav., Tv. | |||||
864 | 0 | s/([^N])Pq\./$1Pq+/g; # Parque (cuidado com CNPq) | |||||
865 | 0 | s/ pq\./ pq+/g; # parque | |||||
866 | 0 | s/Jd\./Jd+/g; # jardim | |||||
867 | 0 | s/Ft\./Ft+/g; # forte | |||||
868 | 0 | s/Cj\./Cj+/g; # conjunto | |||||
869 | 0 | s/ ([lc])j\./ $1j+/g; # conjunto ou loja | |||||
870 | # $par=~s/ al\./ al+/g; # alameda tem que ir para depois de et.al... | ||||||
871 | |||||||
872 | # Remover aqui uns warningzitos | ||||||
873 | 0 | s/Tel\./Tel+/g; # Tel. | |||||
874 | 0 | s/Tel(e[fm])\./Tel$1+/g; # Telef., Telem. | |||||
875 | 0 | s/ tel\./ tel+/g; # tel. | |||||
876 | 0 | s/ tel(e[fm])\./ tel$1+/g; # telef., telem. | |||||
877 | 0 | s/Fax\./Fax+/g; # Fax. | |||||
878 | 0 | s/ cx\./ cx+/g; # caixa | |||||
879 | |||||||
880 | # abreviaturas greco-latinas | ||||||
881 | 0 | s/ a\.C\./ a+C+/g; | |||||
882 | 0 | s/ a\.c\./ a+c+/g; | |||||
883 | 0 | s/ d\.C\./ d+C+/g; | |||||
884 | 0 | s/ d\.c\./ d+c+/g; | |||||
885 | 0 | s/ ca\./ ca+/g; | |||||
886 | 0 | s/etc\.([.,;])/etc+$1/g; | |||||
887 | 0 | s/etc\.\)([.,;])/etc+)$1/g; | |||||
888 | 0 | s/etc\. --( *[a-záéíóúâêà,])/etc+ --$1/g; | |||||
889 | 0 | s/etc\.(\)*) ([^A-ZÀÁÉÍÓÂÊ])/etc+$1 $2/g; | |||||
890 | 0 | s/ et\. *al\./ et+al+/g; | |||||
891 | 0 | s/ al\./ al+/g; # alameda | |||||
892 | 0 | s/ q\.b\./ q+b+/g; | |||||
893 | 0 | s/ i\.e\./ i+e+/g; | |||||
894 | 0 | s/ibid\./ibid+/g; | |||||
895 | 0 | s/ id\./ id+/g; # se calhar é preciso ver se não vem sempre precedido de um ( | |||||
896 | 0 | s/op\.( )*cit\./op+$1cit+/g; | |||||
897 | 0 | s/P\.S\./P+S+/g; | |||||
898 | |||||||
899 | # unidades de medida | ||||||
900 | 0 | s/([0-9][hm])\. ([^A-ZÀÁÉÍÓÚÂÊ])/$1+ $2/g; # 19h., 24m. | |||||
901 | 0 | s/([0-9][km]m)\. ([^A-ZÀÁÉÍÓÚÂÊ])/$1+ $2/g; # 20km., 24mm. | |||||
902 | 0 | s/([0-9]kms)\. ([^A-ZÀÁÉÍÓÚÂÊ])/$1+ $2/g; # kms. !! | |||||
903 | 0 | s/(\bm)\./$1+/g; # metros no MINHO | |||||
904 | |||||||
905 | # outros | ||||||
906 | 0 | s/\(([Oo]rgs*)\.\)/($1+)/g; # (orgs.) | |||||
907 | 0 | s/\(([Ee]ds*)\.\)/($1+)/g; # (eds.) | |||||
908 | 0 | s/séc\./séc+/g; | |||||
909 | 0 | s/pág(s*)\./pág$1+/g; | |||||
910 | 0 | s/pg\./pg+/g; | |||||
911 | 0 | s/pag\./pag+/g; | |||||
912 | 0 | s/ ed\./ ed+/g; | |||||
913 | 0 | s/Ed\./Ed+/g; | |||||
914 | 0 | s/ sáb\./ sáb+/g; | |||||
915 | 0 | s/ dom\./ dom+/g; | |||||
916 | 0 | s/ id\./ id+/g; | |||||
917 | 0 | s/ min\./ min+/g; | |||||
918 | 0 | s/ n\.o(s*) / n+o$1 /g; # abreviatura de numero no MLCC-DEB | |||||
919 | 0 | s/ ([Nn])o\.(s*)\s*([0-9])/ $1o+$2 $3/g; # abreviatura de numero no., No. | |||||
920 | 0 | s/ n\.(s*)\s*([0-9])/ n+$1 $2/g; # abreviatura de numero n. no ANCIB | |||||
921 | 0 | s/ num\. *([0-9])/ num+ $1/g; # abreviatura de numero num. no ANCIB | |||||
922 | 0 | s/ c\. ([0-9])/ c+ $1/g; # c. 1830 | |||||
923 | 0 | s/ p\.ex\./ p+ex+/g; | |||||
924 | 0 | s/ p\./ p+/g; | |||||
925 | 0 | s/ pp\./ pp+/g; | |||||
926 | 0 | s/ art(s*)\./ art$1+/g; | |||||
927 | 0 | s/Min\./Min+/g; | |||||
928 | 0 | s/Inst\./Inst+/g; | |||||
929 | 0 | s/vol(s*)\./vol$1+ /g; | |||||
930 | 0 | s/ v\. *([0-9])/ v+ $1/g; # abreviatura de volume no ANCIB | |||||
931 | 0 | s/\(v\. *([0-9])/\(v+ $1/g; # abreviatura de volume no ANCIB | |||||
932 | 0 | s/^v\. *([0-9])/v+ $1/g; # abreviatura de volume no ANCIB | |||||
933 | 0 | s/Obs\./Obs+/g; | |||||
934 | |||||||
935 | # Abreviaturas de meses | ||||||
936 | 0 | s/(\W)jan\./$1jan+/g; | |||||
937 | 0 | s/\Wfev\./$1fev+/g; | |||||
938 | 0 | s/(\/\s*)mar\.(\s*[0-9\/])/$1mar+$2/g; # a palavra "mar" | |||||
939 | 0 | s/(\W)mar\.(\s*[0-9]+)/$1mar\+$2/g; | |||||
940 | 0 | s/(\W)abr\./$1abr+/g; | |||||
941 | 0 | s/(\W)mai\./$1mai+/g; | |||||
942 | 0 | s/(\W)jun\./$1jun+/g; | |||||
943 | 0 | s/(\W)jul\./$1jul+/g; | |||||
944 | 0 | s/(\/\s*)ago\.(\s*[0-9\/])/$1ago+$2/g; # a palavra inglesa "ago" | |||||
945 | 0 | s/ ago\.(\s*[0-9\/])/ ago+$1/g; # a palavra inglesa "ago./" | |||||
946 | 0 | s/(\W)set\.(\s*[0-9\/])/$1set+$2/g; # a palavra inglesa "set" | |||||
947 | 0 | s/([ \/])out\.(\s*[0-9\/])/$1out+$2/g; # a palavra inglesa "out" | |||||
948 | 0 | s/(\W)nov\./$1nov+/g; | |||||
949 | 0 | s/(\/\s*)dez\.(\s*[0-9\/])/$1dez+$2/g; # a palavra "dez" | |||||
950 | 0 | s/(\/\s*)dez\./$1dez+/g; # a palavra "/dez." | |||||
951 | |||||||
952 | # Abreviaturas inglesas | ||||||
953 | 0 | s/Bros\./Bros+/g; | |||||
954 | 0 | s/Co\. /Co+ /g; | |||||
955 | 0 | s/Co\.$/Co+/g; | |||||
956 | 0 | s/Com\. /Com+ /g; | |||||
957 | 0 | s/Com\.$/Com+/g; | |||||
958 | 0 | s/Corp\. /Corp+ /g; | |||||
959 | 0 | s/Inc\. /Inc+ /g; | |||||
960 | 0 | s/Ltd\. /Ltd+ /g; | |||||
961 | 0 | s/([Mm])r(s*)\. /$1r$2+ /g; | |||||
962 | 0 | s/Ph\.D\./Ph+D+/g; | |||||
963 | 0 | s/St\. /St+ /g; | |||||
964 | 0 | s/ st\. / st+ /g; | |||||
965 | |||||||
966 | # Abreviaturas francesas | ||||||
967 | 0 | s/Mme\./Mme+/g; | |||||
968 | |||||||
969 | # Abreviaturas especiais do Diário do Minho | ||||||
970 | 0 | s/ habilit\./ habilit+/g; | |||||
971 | 0 | s/Hab\./Hab+/g; | |||||
972 | 0 | s/Mot\./Mot+/g; | |||||
973 | 0 | s/\-Ang\./-Ang+/g; | |||||
974 | 0 | s/(\bSp)\./$1+/g; # Sporting | |||||
975 | 0 | s/(\bUn)\./$1+/g; # Universidade | |||||
976 | |||||||
977 | # Abreviaturas especiais do Folha | ||||||
978 | 0 | s/([^'])Or\./$1Or+/g; # alemanha Oriental, evitar d'Or | |||||
979 | 0 | s/Oc\./Oc+/g; # alemanha Ocidental | |||||
980 | |||||||
981 | } | ||||||
982 | |||||||
983 | # tratar dos conjuntos de iniciais | ||||||
984 | 0 | my @siglas_iniciais = ($par =~ /^(?:[A-Z]\. *)+[A-Z]\./); | |||||
985 | 0 | my @siglas_finais = ($par =~ /(?:[A-Z]\. *)+[A-Z]\.$/); | |||||
986 | 0 | my @siglas = ($par =~ m#(?:[A-Z]\. *)+(?:[A-Z]\.)(?=[]\)\s,;:!?/])#g); #trata de conjuntos de iniciais | |||||
987 | 0 | push (@siglas, @siglas_iniciais); | |||||
988 | 0 | push (@siglas, @siglas_finais); | |||||
989 | 0 | my $sigla_antiga; | |||||
990 | 0 | foreach my $sigla (@siglas) { | |||||
991 | 0 | $sigla_antiga = $sigla; | |||||
992 | 0 | $sigla =~ s/\./+/g; | |||||
993 | 0 | $sigla_antiga =~ s/\./\\\./g; | |||||
994 | # print "SIGLA antes: $sigla, $sigla_antiga\n"; | ||||||
995 | 0 | $par =~ s/$sigla_antiga/$sigla/g; | |||||
996 | # print "SIGLA: $sigla\n"; | ||||||
997 | } | ||||||
998 | |||||||
999 | # tratar de pares de iniciais ligadas por hífen (à francesa: A.-F.) | ||||||
1000 | 0 | for ($par) { | |||||
1001 | 0 | s/ ([A-Z])\.\-([A-Z])\. / $1+-$2+ /g; | |||||
1002 | # tratar de iniciais (únicas?) seguidas por ponto | ||||||
1003 | 0 | s/ ([A-Z])\. / $1+ /g; | |||||
1004 | # tratar de iniciais seguidas por ponto | ||||||
1005 | 0 | s/^([A-Z])\. /$1+ /g; | |||||
1006 | # tratar de iniciais seguidas por ponto antes de aspas "D. João | ||||||
1007 | # VI: Um Rei Aclamado" | ||||||
1008 | 0 | s/([("\«])([A-Z])\. /$1$2+ /g; | |||||
1009 | } | ||||||
1010 | |||||||
1011 | # Tratar dos URLs (e também dos endereços de email) | ||||||
1012 | # email= url@url... | ||||||
1013 | # aceito endereços seguidos de /hgdha/hdga.html | ||||||
1014 | # seguidos de /~hgdha/hdga.html | ||||||
1015 | # @urls=($par=~/(?:[a-z][a-z0-9-]*\.)+(?:[a-z]+)(?:\/~*[a-z0-9-]+)*?(?:\/~*[a-z0-9][a-z0-9.-]+)*(?:\/[a-z.]+\?[a-z]+=[a-z0-9-]+(?:\&[a-z]+=[a-z0-9-]+)*)*/gi); | ||||||
1016 | |||||||
1017 | 0 | my @urls = ($par =~ /(?:[a-z][a-z0-9-]*\.)+(?:[a-z]+)(?:\/~*[a-z0-9][a-z0-9.-]+)*(?:\?[a-z]+=[a-z0-9-]+(?:\&[a-z]+=[a-z0-9-]+)*)*/gi); | |||||
1018 | 0 | my $url_antigo; | |||||
1019 | 0 | foreach my $url (@urls) { | |||||
1020 | 0 | $url_antigo = $url; | |||||
1021 | 0 | $url_antigo =~ s/\./\\./g; # para impedir a substituição de P.o em vez de P\.o | |||||
1022 | 0 | $url_antigo =~ s/\?/\\?/g; | |||||
1023 | 0 | $url =~ s/\./+/g; | |||||
1024 | # Se o último ponto está mesmo no fim, não faz parte do URL | ||||||
1025 | 0 | $url =~ s/\+$/./; | |||||
1026 | 0 | $url =~ s/\//\/\/\/\//g; # põe quatro //// | |||||
1027 | 0 | $par =~ s/$url_antigo/$url/; | |||||
1028 | } | ||||||
1029 | # print "Depois de tratar dos URLs: $par\n"; | ||||||
1030 | |||||||
1031 | 0 | for ($par) { | |||||
1032 | # de qualquer maneira, se for um ponto seguido de uma vírgula, é | ||||||
1033 | # abreviatura... | ||||||
1034 | 0 | s/\. *,/+,/g; | |||||
1035 | # de qualquer maneira, se for um ponto seguido de outro ponto, é | ||||||
1036 | # abreviatura... | ||||||
1037 | 0 | s/\. *\./+./g; | |||||
1038 | |||||||
1039 | # tratamento de numerais | ||||||
1040 | 0 | s/([0-9]+)\.([0-9]+)\.([0-9]+)/$1_$2_$3/g; | |||||
1041 | 0 | s/([0-9]+)\.([0-9]+)/$1_$2/g; | |||||
1042 | |||||||
1043 | # tratamento de numerais cardinais | ||||||
1044 | # - tratar dos números com ponto no início da frase | ||||||
1045 | 0 | s/^([0-9]+)\. /$1+ /g; | |||||
1046 | # - tratar dos números com ponto antes de minúsculas | ||||||
1047 | 0 | s/([0-9]+)\. ([a-záéíóúâêà])/$1+ $2/g; | |||||
1048 | |||||||
1049 | # tratamento de numerais ordinais acabados em .o | ||||||
1050 | 0 | s/([0-9]+)\.([oa]s*) /$1+$2 /g; | |||||
1051 | # ou expressos como 9a. | ||||||
1052 | 0 | s/([0-9]+)([oa]s*)\. /$1$2+ /g; | |||||
1053 | |||||||
1054 | # tratar numeracao decimal em portugues | ||||||
1055 | 0 | s/([0-9]),([0-9])/$1#$2/g; | |||||
1056 | |||||||
1057 | #print "TRATA: $par\n"; | ||||||
1058 | |||||||
1059 | # tratar indicação de horas | ||||||
1060 | # esta é tratada na tokenização - não separando 9:20 em 9 :20 | ||||||
1061 | } | ||||||
1062 | 0 | return $par; | |||||
1063 | } | ||||||
1064 | |||||||
1065 | |||||||
1066 | sub separa_frases { | ||||||
1067 | 0 | 0 | 1 | my $par = shift; | |||
1068 | |||||||
1069 | # $num++; | ||||||
1070 | |||||||
1071 | 0 | $par = &tratar_pontuacao_interna($par); | |||||
1072 | |||||||
1073 | # print "Depois de tratar_pontuacao_interna: $par\n"; | ||||||
1074 | |||||||
1075 | 0 | for ($par) { | |||||
1076 | |||||||
1077 | # primeiro junto os ) e os -- ao caracter anterior de pontuação | ||||||
1078 | 0 | s/([?!.])\s+\)/$1\)/g; # pôr "ola? )" para "ola?)" | |||||
1079 | 0 | s/([?!.])\s+\-/$1-/g; # pôr "ola? --" para "ola?--" | |||||
1080 | 0 | s/([?!.])\s+§/$1§/g; # pôr "ola? ..." para "ola?..." | |||||
1081 | 0 | s/§\s+\-/$1-/g; # pôr "ola§ --" para "ola§--" | |||||
1082 | |||||||
1083 | # junto tb o travessão -- `a pelica ' | ||||||
1084 | 0 | s/\-\- \' *$/\-\-\' /; | |||||
1085 | |||||||
1086 | # separar esta pontuação, apenas se não for dentro de aspas, ou | ||||||
1087 | # seguida por vírgulas ou parênteses o a-z estáo lá para não | ||||||
1088 | # separar /asp?id=por ... | ||||||
1089 | 0 | s/([?!]+)([^-\»'´,§?!)"a-z])/$1.$2/g; | |||||
1090 | |||||||
1091 | # Deixa-se o travessão para depois | ||||||
1092 | # print "Depois de tratar do ?!: $par"; | ||||||
1093 | |||||||
1094 | # separar as reticências entre parênteses apenas se forem seguidas | ||||||
1095 | # de nova frase, e se não começarem uma frase elas próprias | ||||||
1096 | 0 | s/([\w?!])§([\»"´']*\)) *([A-ZÁÉÍÓÚÀ])/$1§$2.$3/g; | |||||
1097 | |||||||
1098 | # print "Depois de tratar das retic. seguidas de ): $par"; | ||||||
1099 | |||||||
1100 | # separar os pontos antes de parênteses se forem seguidos de nova | ||||||
1101 | # frase | ||||||
1102 | 0 | s/([\w])\.([)]) *([A-ZÁÉÍÓÚÀ])/$1 + $2.$3/g; | |||||
1103 | |||||||
1104 | # separar os pontos ? e ! antes de parênteses se forem seguidos de | ||||||
1105 | # nova frase, possivelmente tb iniciada por abre parênteses ou | ||||||
1106 | # travessão | ||||||
1107 | 0 | s/(\w[?!]+)([)]) *((?:\( |\-\- )*[A-ZÁÉÍÓÚÀ])/$1 $2.$3/g; | |||||
1108 | |||||||
1109 | # separar as reticências apenas se forem seguidas de nova frase, e | ||||||
1110 | # se não começarem uma frase elas próprias trata também das | ||||||
1111 | # reticências antes de aspas | ||||||
1112 | 0 | s/([\w\d!?])\s*§(["\»'´]*) ([^\»"'a-záéíóúâêàäëïöü,;?!)])/$1§$2.$3/g; | |||||
1113 | 0 | s/([\w\d!?])\s*§(["\»'´]*)\s*$/$1§$2. /g; | |||||
1114 | |||||||
1115 | # aqui trata das frases acabadas por aspas, eventualmente tb | ||||||
1116 | # fechando parênteses e seguidas por reticências | ||||||
1117 | 0 | s/([\w!?]["\»'´])§(\)*) ([^\»"a-záéíóúâêàäëïöü,;?!)])/$1§$2.$3/g; | |||||
1118 | |||||||
1119 | #print "depois de tratar das reticencias seguidas de nova frase: $par\n"; | ||||||
1120 | |||||||
1121 | # tratar dos dois pontos: apenas se seguido por discurso directo | ||||||
1122 | # em maiúsculas | ||||||
1123 | 0 | s/: \«([A-ZÁÉÍÓÚÀ])/:.\«$1/g; | |||||
1124 | 0 | s/: (\-\-[ \«]*[A-ZÁÉÍÓÚÀ])/:.$1/g; | |||||
1125 | |||||||
1126 | # tratar dos dois pontos se eles acabam o parágrafo (é preciso pôr | ||||||
1127 | # um espaço) | ||||||
1128 | 0 | s/:\s*$/:. /; | |||||
1129 | |||||||
1130 | # tratar dos pontos antes de aspas | ||||||
1131 | 0 | s/\.(["\»'´])([^.])/+$1.$2/g; | |||||
1132 | |||||||
1133 | # tratar das aspas quando seguidas de novas aspas | ||||||
1134 | 0 | s/\»\s*[\«"]/\». \«/g; | |||||
1135 | |||||||
1136 | # tratar de ? e ! seguidos de aspas quando seguidos de maiúscula | ||||||
1137 | # eventualmente iniciados por abre parênteses ou por travessão | ||||||
1138 | 0 | s/([?!])([\»"'´]) ((?:\( |\-\- )*[A-ZÁÉÍÓÚÀÊÂ])/$1$2. $3/g; | |||||
1139 | |||||||
1140 | # separar os pontos ? e ! antes de parênteses e possivelmente | ||||||
1141 | # aspas se forem o fim do parágrafo | ||||||
1142 | 0 | s/(\w[?!]+)([)][\»"'´]*) *$/$1 $2./; | |||||
1143 | |||||||
1144 | # tratar dos pontos antes de aspas precisamente no fim | ||||||
1145 | 0 | s/\.([\»"'´])\s*$/+$1. /g; | |||||
1146 | |||||||
1147 | # tratar das reticências e outra pontuação antes de aspas ou | ||||||
1148 | # plicas precisamente no fim | ||||||
1149 | 0 | s/([!?§])([\»"'´]+)\s*$/$1$2. /g; | |||||
1150 | |||||||
1151 | #tratar das reticências precisamente no fim | ||||||
1152 | 0 | s/§\s*$/§. /g; | |||||
1153 | |||||||
1154 | # tratar dos pontos antes de parêntesis precisamente no fim | ||||||
1155 | 0 | s/\.\)\s*$/+\). /g; | |||||
1156 | |||||||
1157 | # aqui troco .) por .). ... | ||||||
1158 | 0 | s/\.\)\s/+\). /g; | |||||
1159 | } | ||||||
1160 | |||||||
1161 | # tratar de parágrafos que acabam em letras, números, vírgula ou | ||||||
1162 | # "-", chamando-os fragmentos #ALTERACAO | ||||||
1163 | 0 | my $fragmento; | |||||
1164 | 0 | 0 | if ($par =~/[A-Za-záéíóúêãÁÉÍÓÚÀ0-9\),-][\»\"\'´>]*\s*\)*\s*$/) { | ||||
1165 | 0 | $fragmento = 1 | |||||
1166 | } | ||||||
1167 | |||||||
1168 | 0 | for ($par) { | |||||
1169 | # se o parágrafo acaba em "+", deve-se juntar "." outra vez. | ||||||
1170 | 0 | s/([^+])\+\s*$/$1+. /; | |||||
1171 | |||||||
1172 | # se o parágrafo acaba em abreviatura (+) seguido de aspas ou parêntesis, deve-se juntar "." | ||||||
1173 | 0 | s/([^+])\+\s*(["\»'´\)])\s*$/$1+$2. /; | |||||
1174 | |||||||
1175 | # print "Parágrafo antes da separação: $par"; | ||||||
1176 | } | ||||||
1177 | |||||||
1178 | 0 | my @sentences = split /\./,$par; | |||||
1179 | 0 | 0 | 0 | if (($#sentences > 0) and not $fragmento) { | |||
1180 | 0 | pop(@sentences); | |||||
1181 | } | ||||||
1182 | |||||||
1183 | 0 | my $resultado = ""; | |||||
1184 | # para saber em que frase pôr |
||||||
1185 | 0 | my $num_frase_no_paragrafo = 0; | |||||
1186 | 0 | foreach my $frase (@sentences) { | |||||
1187 | 0 | $frase = &recupera_ortografia_certa($frase); | |||||
1188 | |||||||
1189 | 0 | 0 | 0 | if (($frase=~/[.?!:;][\»"'´]*\s*$/) or | |||
0 | 0 | ||||||
1190 | ($frase=~/[.?!] *\)[\»"'´]*$/)) { | ||||||
1191 | # frase normal acabada por pontuação | ||||||
1192 | 0 | $resultado .= " |
|||||
1193 | } | ||||||
1194 | |||||||
1195 | elsif (($fragmento) and ($num_frase_no_paragrafo == $#sentences)) { | ||||||
1196 | 0 | $resultado .= " |
|||||
1197 | 0 | $fragmento = 0; | |||||
1198 | } | ||||||
1199 | else { | ||||||
1200 | 0 | $resultado .= " |
|||||
1201 | } | ||||||
1202 | 0 | $num_frase_no_paragrafo++; | |||||
1203 | } | ||||||
1204 | |||||||
1205 | 0 | return $resultado; | |||||
1206 | } | ||||||
1207 | |||||||
1208 | |||||||
1209 | sub recupera_ortografia_certa { | ||||||
1210 | # os sinais literais de + são codificados como "++" para evitar | ||||||
1211 | # transformação no ponto, que é o significado do "+" | ||||||
1212 | |||||||
1213 | 0 | 0 | 1 | my $par = shift; | |||
1214 | |||||||
1215 | 0 | for ($par) { | |||||
1216 | 0 | s/([^+])\+(?!\+)/$1./g; # um + não seguido por + | |||||
1217 | 0 | s/\+\+/+/g; | |||||
1218 | 0 | s/^§(?!§)/.../g; # se as reticências começam a frase | |||||
1219 | 0 | s/([^§(])§(?!§)\)/$1... \)/g; # porque se juntou no separa_frases | |||||
1220 | # So nao se faz se for (...) ... | ||||||
1221 | 0 | s/([^§])§(?!§)/$1.../g; # um § não seguido por § | |||||
1222 | 0 | s/§§/§/g; | |||||
1223 | 0 | s/_/./g; | |||||
1224 | 0 | s/#/,/g; | |||||
1225 | 0 | s#////#/#g; #passa 4 para 1 | |||||
1226 | 0 | s/([?!])\-/$1 \-/g; # porque se juntou no separa_frases | |||||
1227 | 0 | s/([?!])\)/$1 \)/g; # porque se juntou no separa_frases | |||||
1228 | } | ||||||
1229 | 0 | return $par; | |||||
1230 | } | ||||||
1231 | |||||||
1232 | |||||||
1233 | 1; | ||||||
1234 | __END__ |