# -*- coding: utf-8 -*-
# text alignment program
# derived from align.py
# licence: GPL
# version: 3
import os, re
import difflib
import subprocess
import pickle
import pywikibot as bot
it=bot.Site("it","wikisource")
# tiraboschi
djvuI="tirab/djvu/Tiraboschi - Storia della letteratura italiana, Tomo I, Classici italiani, 1822, I.djvu"
djvuII="tirab/djvu/Tiraboschi - Storia della letteratura italiana, Tomo II, Classici italiani, 1823, II.djvu"
djvuIII="tirab/djvu/Tiraboschi_-_Storia_della_letteratura_italiana,_Tomo_III,_Classici_italiani,_1823,_III.djvu"
djvuIV="tirab/djvu/Tiraboschi_-_Storia_della_letteratura_italiana,_Tomo_IV,_Classici_italiani,_1823,_IV.djvu"
djvuV="tirab/djvu/Tiraboschi - Storia della letteratura italiana, Tomo V, parte 1, Classici Italiani, 1823, V.djvu"
djvuVI="tirab/djvu/Tiraboschi_-_Storia_della_letteratura_italiana,_Tomo_V,_parte_2,_Classici_italiani,_1823,_VI.djvu"
djvuVII="tirab/djvu/Tiraboschi_-_Storia_della_letteratura_italiana,_Tomo_VI,_parte_1,_Classici_italiani,_1824,_VII.djvu"
djvuVIII="tirab/djvu/Tiraboschi_-_Storia_della_letteratura_italiana,_Tomo_VI,_parte_2,_Classici_italiani,_1824,_VIII.djvu"
djvuX="tirab/djvu/Tiraboschi_-_Storia_della_letteratura_italiana,_Tomo_VII,_parte_1,_Classici_italiani,_1824,_X.djvu"
djvuXI="tirab/djvu/Tiraboschi_-_Storia_della_letteratura_italiana,_Tomo_VII,_parte_2,_Classici_italiani,_1824,_XI.djvu"
djvuXII="tirab/djvu/Tiraboschi_-_Storia_della_letteratura_italiana,_Tomo_VII,_parte_3,_Classici_italiani,_1824,_XII.djvu"
djvuXIII="tirab/djvu/Tiraboschi_-_Storia_della_letteratura_italiana,_Tomo_VII,_parte_4,_Classici_italiani,_1824,_XIII.djvu"
djvuIX="tirab/djvu/Tiraboschi - Storia della letteratura italiana, Tomo VI, parte 3, Classici italiani, 1824, IX.djvu"
djvuV="tirab/djvu/Tiraboschi - Storia della letteratura italiana, Tomo V, parte 1, Classici Italiani, 1823, V.djvu"
djvuXVI="tirab/djvu/Tiraboschi_-_Storia_della_letteratura_italiana,_Tomo_IX,_Indici,_Classici_italiani,_1826,_XVI.djvu"
djvuXIV="tirab/djvu/Tiraboschi_-_Storia_della_letteratura_italiana,_Tomo_VIII,_parte_1,_Classici_italiani,_1824,_XIV.djvu"
djvuXV="tirab/djvu/Tiraboschi_-_Storia_della_letteratura_italiana,_Tomo_VIII,_parte_2,_Classici_italiani,_1824,_XV.djvu"
txtXVI="tirab/txt/Volume_XVI.txt"
txtI="tirab/txt/tomo_1.txt"
txtII="tirab/txt/tomo_2.txt"
txtIII="tirab/txt/tomo_3.txt"
txtIV="tirab/txt/Volume_IV.txt"
txtIII="tirab/txt/tomo_3.txt"
txtX="tirab/txt/Volume_10.txt"
txtIX="tirab/txt/Volume_IX.txt"
txtXIII="tirab/txt/Volume_XIII.txt"
txtXII="tirab/txt/Volume_XII.txt"
txtXI="tirab/txt/Volume_XI.txt"
txtV="tirab/txt/tomo_V.txt"
txtVI="tirab/txt/tomo_VI.txt"
txtVIII="tirab/txt/Tomo_VIII.txt"
# Nuova versione, gestisce i tag annidati; x e' la parte "aspecifica" del
# tag di apertura (es: {{ cercando {{Intestazione| )
def find_stringa(stringa,idi,idf,dc=0,x=None,side="left"):
if side=="right":
idip=stringa.rfind(idi)
else:
idip=stringa.find(idi)
idfp=stringa.find(idf,idip+len(idi))+len(idf)
if idip>-1 and idfp>0:
if x!=None:
while stringa[idip:idfp].count(x)>stringa[idip:idfp].count(idf):
if stringa[idip:idfp].count(x)>stringa[idip:idfp].count(idf):
idfp=stringa.find(idf,idfp)+len(idf)
if dc==0:
vvalore=stringa[idip+len(idi):idfp-len(idf)]
else:
vvalore=stringa[idip:idfp]
else:
vvalore=""
return vvalore
def produci_lista(testo,idi,idf,dc=1,inizio=None):
t=testo[:]
lista=[]
while not find_stringa(t,idi,idf,1,inizio)=="":
el=find_stringa(t,idi,idf,1,inizio)
t=t.replace(el,"",1)
if dc==0:
el=find_stringa(el,idi,idf,0,inizio)
lista.append(el)
return lista
def parseTemplate(template):
elementi={}
n=1
template=template.strip()[2:-2]
#codifica link
x=produci_lista(template,"[[","]]",1)
for i in x:
key="##%d##" % (n)
elementi[key]=i
template=template.replace(i,key)
n+=1
#codifica template
x=produci_lista(template,"{{","}}",1,"{{")
for i in x:
key="##%d##" % (n)
elementi[key]=i
template=template.replace(i,key)
n+=1
#codifica url
x=produci_lista(template,"[","]",1)
for i in x:
key="##%d##" % (n)
elementi[key]=i
template=template.replace(i,key)
n+=1
template=template.split("|")
#normalizzazione parametri
n=1
for i in range(1,len(template)):
if not "=" in template[i]:
template[i]=str(n)+" = "+template[i]
n+=1
template[i]=template[i].strip()
for j in elementi:
template[i]=template[i].replace(j,elementi[j])
templateDict={}
templateDict["nome"]=template[0].strip()
r=re.compile(" *= *")
for i in range(1,len(template)):
tv=r.split(template[i])
templateDict[tv[0].strip()]=tv[1].strip()
return templateDict
# elimina l'escaping dei caratteri speciali nel djvu text
def unquote_text_from_djvu(text):
#text = text.replace(u'\\r', u'\r')
text = text.replace(u'\\n', u'\n')
text = text.replace(u'\\"', u'"')
text = text.replace(u'\\\\', u'\\')
text = text.replace(u'\\037', u'\n')
text = text.replace(u'\\035', u'')
text = text.replace(u'\\013', u'')
text = text.replace(u'\\t', u' ')
text = text.rstrip(u'\n')
return text
# estrae lo strato testo in datail page, e produce la lista data dei testi
# delle pagine (pagina 1 in data[0]);
# il file djvu deve essere scaricato nella cartella locale
def extract_djvu_text(filename):
print "extracting text layer"
if type(filename) == type(u''):
filename = filename.encode('utf-8')
#utils.copy_file_from_url(url, filename, sha1)
data = []
# GTK app are very touchy
os.environ['LANG'] = 'en_US.UTF8'
comando='djvutxt --detail=page "%s" text.txt' % (unicode(filename,"utf-8").encode("latin-1"))
result=os.system(comando)
print comando, result
text=open("text.txt").read()
for t in re.finditer(u'\((page -?\d+ -?\d+ -?\d+ -?\d+[ \n]+"(.*)"[ ]*|)\)\n', text):
t = unicode(t.group(1), 'utf-8', 'replace')
t = re.sub(u'^page \d+ \d+ \d+ \d+[ \n]+"', u'', t)
t = re.sub(u'"[ ]*$', u'', t)
t = unquote_text_from_djvu(t)
# proviamo ad aggirare il bug logico
if len(t)<150:
t=""
data.append(t)
# os.remove(filename)
return data
def extract_pdf_text(filename):
print "extracting text layer from pdf"
if type(filename) == type(u''):
filename = filename.encode('utf-8')
#utils.copy_file_from_url(url, filename, sha1)
data = []
# GTK app are very touchy
os.environ['LANG'] = 'en_US.UTF8'
comando='pdftotext -enc UTF-8 "%s" text.txt' % (filename)
result=os.system(comando)
print comando, result
text=open("text.txt").read()
text=unicode(text,"utf-8")
text=text.replace(u"¬ ","")
data=text.split(u"\x0c")
# os.remove(filename)
return data
# restituisce e stampa un messaggio di errore
def ret_val(error, text):
if error:
print "Error: %d, %s" % (error, text)
return { 'error' : error, 'text' : text }
E_ERROR = 1
E_OK = 0
# It's possible to get a name collision if two different wiki have local
# file with the same name but different contents. In this case the cache will
# be ineffective but no wrong data can be used as we check its sha1.
def get_djvu(cache, mysite, djvuname, check_timestamp = False):
print "get_djvu", repr(djvuname)
djvuname = djvuname.replace(" ", "_")
cache_filename = djvuname + '.dat'
obj = cache.get(cache_filename)
if not obj:
print "CACHE MISS"
filepage = copy_File.get_filepage(mysite, djvuname)
if not filepage:
# can occur if File: has been deleted
return None
try:
url = filepage.fileUrl()
obj = extract_djvu_text(url, djvuname, filepage.getFileSHA1Sum())
except:
utils.print_traceback("extract_djvu_text() fail")
obj = None
if obj:
cache.set(cache_filename, obj)
else:
return None
else:
if check_timestamp:
filepage = copy_File.get_filepage(mysite, djvuname)
if not filepage:
# can occur if File: has been deleted
return None
sha1 = filepage.getFileSHA1Sum()
if sha1 != obj[0]:
print "OUTDATED FILE"
url = filepage.fileUrl()
try:
obj = extract_djvu_text(url, djvuname, sha1)
cache.set(cache_filename, obj)
except:
return None
return obj[1]
def carica_pcl(nome_file, folder="dati/"):
nome_file=folder+nome_file+".pcl"
f=open(nome_file)
contenuto=pickle.load(f)
f.close()
return contenuto
def salva_pcl(variabile,nome_file="dato",folder="dati/"):
nome_file=folder+nome_file+".pcl"
f=open(nome_file,"w")
pickle.dump(variabile, f)
f.close()
print "Variabile salvata nel file "+nome_file
return
# riunione parole spezzate a fine riga
def dehyphen(testo):
testo=testo.strip().split("\n")
for i in range(len(testo)):
testo[i]=testo[i].rstrip()
testo="\n".join(testo)
testo=testo.replace("-\n","").replace(u"¬\n","")
return testo
# splitting di testo in due liste: parole; parole-non parole
def split(testo):
## p = re.compile(ur'[\W]+', re.U) # lista sequenze caratteri
## fp = re.compile(ur'([\W]+)', re.U) # lista sequenze caratteri e non caratteri
p=re.compile(ur"[;:., -()\n\t]+",re.U)
fp=re.compile(ur"([;:., -()\n\t]+)",re.U)
testo_p=p.split(testo)
testo_fp=fp.split(testo)
return [testo_p, testo_fp]
def pos(t1,t2,i):
pos=i*2
if t1[0]=="":
pos+=1
return pos
# ricostruzione del testo dalle liste testo_p (con eventuali elementi modificati), testo_fp
def rebuild(l1,l2,verbose=False):
if l1[0]=="": # caso testo inizia con non-parola
r=range(1,len(l1))
else:
r=range(len(l1))
for i in r:
if verbose:
print l1[i],l2[i*2]
l2[i*2]=l1[i]
testo="".join(l2)
return testo
# restituisce testo1 e testo2 splittatti e la lista degli unmatching blocks
def match(testo1,testo2):
s = difflib.SequenceMatcher()
t1=dehyphen(testo1).strip()
t2=dehyphen(testo2)
t1s=split(t1)
t2s=split(t2)
s.set_seqs(t1s[0],t2s[0])
mb=s.get_matching_blocks()
len_t1s=mb[len(mb)-1][0]
offset=0
unmatching_blocks=[]
mbi=0 # indice degli elementi di mb
ao=bo=0 # offset iniziale di a e b
while True:
al=mb[mbi][0]-ao
bl=mb[mbi][1]-bo
if al>0 and bl>0:
unmatching_blocks.append([ao, al, bo, bl])
ao=mb[mbi][0]+mb[mbi][2]
bo=mb[mbi][1]+mb[mbi][2]
mbi+=1
if mbi>len(mb)-1:
print "fine"
break
return (t1s,t2s,unmatching_blocks)
# riceve a, b, um dalla funzione match; filtra gli elementi um scegliendo quelli "semplici",
# per ora di lunghezza uguale; restituisce il testo corretto e ricostruito
def output(a,b,um,noDigits):
for blocco in um:
#selezione elementi unmatching "semplici"
if blocco[1] != blocco[3]:
if abs(blocco[1]-blocco[3])<3:
print "**** vedi:",a[0][blocco[0]:blocco[0]+blocco[1]],b[0][blocco[2]:blocco[2]+blocco[3]]
if blocco[1]==2 and blocco[3]==1:
offset=pos(a[0],a[1],blocco[0])
print "********", a[1][offset:offset+3]
continue
print a[0][blocco[0]:blocco[0]+blocco[1]],b[0][blocco[2]:blocco[2]+blocco[3]]
if blocco[1]>2:
lista_a=a[0][blocco[0]:blocco[0]+blocco[1]]
lista_b=b[0][blocco[2]:blocco[2]+blocco[3]]
if simil(" ".join(lista_a)," ".join(lista_b),2)<50 :
if not simill(lista_a, lista_b):
conferma=raw_input("sequenza molto diversa, confermi match?")
if len(conferma)!=1 or (not conferma in ("sSyY")):
continue
for i in range(blocco[1]):
#esclusione differenze solo caso carattere
# differenza solo in mM o probabile abbreviazione in b
if a[0][blocco[0]+i].lower() != b[0][blocco[2]+i].lower():
if len(a[0][blocco[0]+i])-len(b[0][blocco[2]+i]) > 2:
print "probabile abbreviatura per lunghezza"
elif a[0][blocco[0]+i].startswith(b[0][blocco[2]+i]):
print "probabile abbreviatura per identità iniziale"
else:
if noDigits and b[0][blocco[2]+i].isdigit():
print "numero, ignoro, correggo: ",a[0][blocco[0]+i],
a[0][blocco[0]+i]=a[0][blocco[0]+i].replace("i","1")\
.replace("I","1")\
.replace("l","1")\
.replace("o","0")\
.replace(u"°","0")
print " in ",a[0][blocco[0]+i]
else:
print " ",a[0][blocco[0]+i],b[0][blocco[2]+i]
a[0][blocco[0]+i]=b[0][blocco[2]+i]
else:
print "differenza esclusiva maiuscole-minuscole"
return rebuild(a[0],a[1])
def simil(a,b,c=4):
punti=0
try:
for i in range(len(a)-c):
if a[i:i+c]in b:
punti+=1
s1=punti*100/(len(a)-c)
punti=0
x=a
a=b
b=x
for i in range(len(a)-c):
if a[i:i+c]in b:
punti+=1
s2=punti*100/(len(a)-c)
return int((s1+s2)/2)
except:
return -1
def simill(a,b,f=1):
# a e b sono liste di stringhe di uguale lunghezza
# f è un indice di somiglianza (1: max differenza media di lunghezza di 1 carattere per parola);
# il valore 1 è molto conservativo, max suggerito 1.5
delta=0
for i in range(len(a)):
delta+=abs(len(a[i])-len(b[i]))
return delta<=len(a)*f
def cleanup(testo):
sostNorm=u''' ) )
( (
: :
; ;
. .
? ?
! !
'\t’'''.split("\n")
for i in range(len(sostNorm)):
sostNorm[i]=sostNorm[i].split("\t")
for s in sostNorm:
testo=testo.replace(s[0],s[1])
testo=re.sub(ur"([^aeiouAEIOU])([’']) ([aeiouAEIOU])",r"\1\2\3",testo)
testo=re.sub(ur"([aeiouAEIOU])([’'])([^ \naeiouAEIOU])",r"\1\2 \3",testo)
return testo
def maf(djvu=None, ini=1, fin=1000, txt=None,load=False, doMatch=True, exists=True, noDigits=False):
## if load:
## import pywikibot as bot
## it=bot.Site("it","wikisource")
testo=""
if djvu==None:
djvu="tirab/djvu/Tiraboschi - Storia della letteratura italiana, Tomo I, Classici italiani, 1822, I.djvu"
if txt==None:
txt="tirab/txt/prova1.txt"
# estrazione testo (formato data)
pagine=extract_djvu_text(djvu)
if doMatch: # viene eseguito il match and fix
t2=unicode(open(txt).read(),"utf-8")
t2=cleanup(t2)
for numeroPagina in range(ini,fin):
basePagina=djvu
if "/" in basePagina:
basePagina=basePagina[basePagina.rfind("/")+1:]
nomePagina="Pagina:"+basePagina+"/"+str(numeroPagina)
if exists:
pag=bot.Page(it,nomePagina)
if pag.exists():
if "{{" in pag.get() or not 'level="1"' in pag.get():
print "Pagina ",pag.title(), "formattata, ignoro"
continue
print "\n==[["+nomePagina+"]]==\n"
t1=pagine[numeroPagina -1].replace("%","@")
t1=cleanup(t1)
t1s,t2s,um=match(t1,t2)
testoCorretto=output(t1s,t2s,um,noDigits).replace("@","%")
#print "==[["+nomePagina+"]]==\n"+testoCorretto
testo+= "\n==[["+nomePagina+"]]==\n"+testoCorretto
#print "\n==[["+nomePagina+"]]==\n"
if load and exists:
# disabilito blocco sovrascrittura
#if (not pg.exists()) or ('level="1"' in pg.get() and not "{{" in pg.get()):
#pg=bot.Page(it,nomePagina)
pag.put(testoCorretto, "Testo ottenuto con Match and Fix 2")
else: # viene eseguita la sola esportazione dell'OCR con codici Split
basePagina=djvu
testo=""
if "/" in basePagina:
basePagina=basePagina[basePagina.rfind("/")+1:]
for numeroPagina in range(ini,fin):
t1=pagine[numeroPagina -1]
nomePagina="Pagina:"+basePagina+"/"+str(numeroPagina)
testo+="\n==[["+nomePagina+"]]==\n"+t1
open("tirab/output/testoSplit.txt","w").write(testo.encode("utf-8"))
print
print "Testo con codici split salvato in tirab/output/testoSplit.txt"
return
# funzione che produce l'ewlenco delle pagine con link Pg errati (con terzo parametro vuoto)
def cerca():
base="Pagina:Tiraboschi - Storia della letteratura italiana, Tomo IX, Indici, Classici italiani, 1826, XVI.djvu/"
for i in range(1, 416):
testo=bot.Page(it, base+str(i)).get()
e=find_stringa(testo, "{{Pg|","|}}",1,"{{")
if e!="":
print i,
print
return