Questo è abbastanza semplice da fare, a seconda di come è strutturato l'input. Supponiamo di avere un file come
Legalese Introduction
(1) Some Legalese Section
With another paragraph inside it
(a) With some sub-paragraph
(I) Some other statutes
(II) Some other statutes
(2) Another Section
Possiamo dividere facilmente questo file in paragrafi e quindi passarci sopra. Per ogni paragrafo con qualche enumerazione, possiamo verificare se questo incrementa il contatore del livello di numerazione corrente. Se è così, eseguiamo questa operazione ed emettiamo un ID.
Altrimenti, questo aggiunge un altro livello o chiude uno o più livelli.
Facciamo questo modellando i contatori con uno stack . Su ciascun paragrafo enumerato, inseriamo o spingiamo elementi nello stack.
La difficoltà sta nel decidere se due enumerazioni siano dello stesso schema di numerazione, ad es. L
e I
possono essere latenti maiuscoli (A, B, C, ...) o numeri romani (I, II, III, ...). Potresti quindi voler trasformare entrambi nel loro valore numerico e affermare che non sono solo dello stesso schema ma sono anche consecutivi.
Ecco uno script Perl di base che analizzerebbe l'esempio precedente, ma avrebbe difficoltà con input più complessi per i motivi citati:
use strict;
use warnings;
use HTML::Entities qw< encode_entities >;
local $/ = ''; # paragraph mode
my @stack;
while(my $section = <>) {
$section =~ s/^\s+//;
$section =~ s/\s+$//;
my ($number) = $section =~ m/[(] ([A-Z]+|[a-z]+|[0-9]+|[IVXLCDM]+) [)]/x;
if (not $number) {
print "<p>", encode_entities($section), "</p>\n";
next;
}
# check if the numbering is a continuation of the current or another level
if (@stack and grep { compatible($_, $number) } @stack) {
pop @stack until compatible($stack[-1], $number);
$stack[-1] = $number
}
# open a new level
else {
push @stack, $number;
}
my $id = join "-", "section", @stack;
print qq(<p id="$id">), encode_entities($section), "</p>\n";
}
sub compatible {
my ($prev, $this) = @_;
(my $expected = $prev)++; # increment is magic and works on strings too.
no warnings 'numeric';
# numbers
return 1 if not (grep /[^0-9]/, $prev, $this) and $expected == $this;
# upper latin
return 1 if not (grep /[^A-Z]/, $prev, $this) and $expected eq $this;
# lower latin
return 1 if not (grep /[^a-z]/, $prev, $this) and $expected eq $this;
# roman numerals
return 1 if not (grep /[^IVXLCDM]/, $prev, $this); # TODO check consecutive
return 0;
}