# -*- coding: utf-8 -*-
# text alignment program
# author : thomasv1 at gmx dot de
# author : phe at some dot where
# licence : GPL
import os, re
import difflib
import subprocess
import pickle
#funzioni dummy
def utils():
return
def copy_File():
return
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], maxsplit=1)
templateDict[tv[0].strip()]=tv[1].strip()
return templateDict
def rebuildTemplate(td, areadati=None):
template="{{"+td["nome"]+"\n"
for d in list(td.keys())[1:]:
if d.isdigit() and not "=" in td[d]:
template+="| "+td[d]+"\n"
else:
template+="| "+ d+" = "+td[d]+"\n"
template+="}}"
return template
# calcola la qualità del match (da 0 a 1)
def match_page(target, source):
s = difflib.SequenceMatcher()
text1 = source
text2 = target
p = re.compile(r'[\W]+')
text1 = p.split(text1)
text2 = p.split(text2)
s.set_seqs(text1,text2)
ratio = s.ratio()
return ratio
# elimina l'escaping dei caratteri speciali nel djvu text
def unquote_text_from_djvu(text):
#text = text.replace('\\r', '\r')
text = text.replace('\\n', '\n')
text = text.replace('\\"', '"')
text = text.replace('\\\\', '\\')
text = text.replace('\\037', '\n')
text = text.replace('\\035', '')
text = text.replace('\\013', '')
text = text.rstrip('\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(''):
## 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'
# FIXME: check return code
## ls = subprocess.Popen([ 'djvutxt', filename, '--detail=page'], stdout=subprocess.PIPE, close_fds = True)
## text = ls.stdout.read()
## ls.wait()
# comando="djvutxt --detail=page %s text.txt" % (unicode(filename,"utf-8").encode("latin-1"))
comando="djvutxt --detail=page %s text.txt" % filename
result=os.system(comando)
print(comando, result)
text=open("text.txt").read()
for t in re.finditer(r'\((page -?\d+ -?\d+ -?\d+ -?\d+[ \n]+"(.*)"[ ]*|)\)\n', text):
#t = unicode(t.group(1), 'utf-8', 'replace')
t=t.group(1)
t = re.sub('^page \d+ \d+ \d+ \d+[ \n]+"', '', t)
t = re.sub('"[ ]*$', '', 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(''):
## 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'
# FIXME: check return code
## ls = subprocess.Popen([ 'djvutxt', filename, '--detail=page'], stdout=subprocess.PIPE, close_fds = True)
## text = ls.stdout.read()
## ls.wait()
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
# routine fondamentale; valuta il match ed esegue il caricamento in nsPagina, lasciate ogni speranza...
# returns result, status
# target è il testo di cui fare il match.
# cached_txt è la lista dei testi delle pagine djvu
# djvuname e number sono ovvi
# verbose è opzione debug che stampa il testo matchato.
# prefix è il nome locale di nsPagina
# step è boh, default 1
# se E_OK restituisce il testo a cui sono intercalati i codici match
def do_match(target, cached_text, djvuname, number, verbose=False, prefix="Pagina", step=1, oldText=True):
s = difflib.SequenceMatcher()
offset = 0
output = ""
is_poem = False
try:
last_page = cached_text[number - ((step+1)//2)]
except:
return ret_val(E_ERROR, "Unable to retrieve text layer for page: " + str(number))
# ciclo pagina per pagina
for pagenum in range(number, min(number + 1000, len(cached_text)), step):
if pagenum - number == 10 and offset == 0:
return ret_val(E_ERROR, "error : could not find a text layer.")
# verifica match
page1 = last_page
last_page = page2 = cached_text[pagenum + (step//2)]
try:
page3=cached_text[pagenum + 2*(step//2)]
except:
page3=""
try:
page4=cached_text[pagenum + 3*(step//2)]
except:
page4=""
text1 = page1+page2+page3+page4
text2 = target[offset:offset+ int(1.5*len(text1))]
text3 = text2 # salvo in text3 il testo originale
if oldText:
text2 = text2.replace("s","f") # trasformazione oldText
p = re.compile(r'[\W]+', re.U) # lista sequenze caratteri
fp = re.compile(r'([\W]+)', re.U) # lista sequenze caratteri e non caratteri
ftext1 = fp.split(text1) # nelle due pagine djvu
ftext2 = fp.split(text2) # nel testo target modificato
ftext3 = fp.split(text3) # nel testo target nel testo originale
page1 = p.split(page1) #lista parole in pagina corrente
text1 = p.split(text1) #lista parole in pagina corrente + successiva
text2 = p.split(text2) #lista parole blocco testo
s.set_seqs(text1,text2)
# produce triplette degli indici dei blocchi corrispondenti
# (i, j, n), and means that a[i:i+n] == b[j:j+n]
# l'ultima è dummy (len(a), len(b), 0).
mb = s.get_matching_blocks()
if len(mb) < 2: # nessun match
print("LEN(MB) < 2, breaking")
break
ccc = mb[-2] #ultimo blocco matching; ccc[0]+ccc[2]=numero delle parole totale in text1 (pagina corrente+pagina successiva)
# no idea what was the purpose of this
#dummy = mb[-1]
ratio = s.ratio()
#print(i, ccc, ratio)
if ratio < 0.10 and len(last_page)>300: #possibile illustrazione con breve didascalia
print("low ratio", ratio)
# return (page1,text1,text2)
break
# CICLO DEBUG
mstr = u""
overflow = False
# elemento per elemento nell'ultimo blocco:
for i in range(ccc[0] + ccc[2]): #parola per parola nella lista text1 (indici)
matched = False
for m in mb: #gruppo matched per gruppo matched
if i >= m[0] and i < m[0]+m[2] : # se l'indice della parola è compresa in un guppo matched...
matched = True
if i >= len(page1): #se la parola è fuori della pagina corrente
overflow = True
break
if not overflow: # se la parola è all'interno della pagina corrente...
ss = ftext1[2*i] #recupero parola (0, 2....)
if matched:
ss =u"\033[1;32m%s\033[0;49m"%ss
if 2*i+1 < len(ftext1):
mstr = mstr + ss + ftext1[2*i+1]
if verbose:
# pywikibot.output(mstr)
print(mstr)
print("--------------------------------")
# costruzione vera e propria del testo matched
ftext2=ftext3[:] # riprendo il testo originale
mstr = ""
no_color = ""
overflow = False
for i in range(ccc[1]+ccc[2]):
matched = False
for m in mb:
if i >= m[1] and i < m[1]+m[2] :
matched = True
if m[0]+i-m[1] >= len(page1):
overflow = True
break
if not overflow:
ss = ftext2[2*i]
if matched:
ss =u"\033[1;31m%s\033[0;49m"%ss
if 2*i+1 < len(ftext2):
mstr = mstr + ss + ftext2[2*i+1]
no_color = no_color + ftext2[2*i] + ftext2[2*i+1] # a no_color viene appesa la parola + il blocco non alfabetico,
# ma solo se overflow è falso
if verbose:
# pywikibot.output(mstr)
print(mstr)
print("====================================")
# creazione separatore; is_poem è vero se nella pagina precedente c'era un poem non chiuso
if is_poem:
sep = u"\n</poem>\n==[["+prefix+":%s/%d]]==\n<poem>\n"%(djvuname,pagenum)
else:
sep = u"\n==[["+prefix+":%s/%d]]==\n"%(djvuname,pagenum)
print("%s/%d" %(djvuname,pagenum))
# Move the end of the last page to the start of the next page
# if the end of the last page look like a paragraph start. 16 char
# width to detect that is a guessed value.
# ?????
no_color = no_color.rstrip()
match = re.match(u"(?ms).*(\n\n.*)$", no_color)
if match and len(match.group(1)) <= 16:
no_color = no_color[:-len(match.group(1))]
else:
match = re.match(u"(?ms).*(\n\w+\W*)$", no_color)
if match:
no_color = no_color[:-(len(match.group(1)) - 1)]
offset += len(no_color) # aggiornamento offset sul target per proseguire dalla prossima pagina
if no_color and no_color[0]=='\n': # eliminazione eventuale acapo in testa a no_color
no_color = no_color[1:]
no_color = no_color.lstrip(' ') # ... e di eventuali spazi
output += sep + no_color # ad output viene aggiunto l separatore ==[[Pagina....]]== e il contenuto di no_color (testo matched)
if no_color.rfind(u"<poem>") > no_color.rfind(u"</poem>"):
is_poem = True
elif no_color.rfind(u"<poem>") < no_color.rfind(u"</poem>"):
is_poem = False
# ciclo pagina per pagina terminato
if offset != 0 and target[offset:]:
if len(target) - offset >= 16:
output += u"\n=== no match ===\n"
output += target[offset:].lstrip(' ')
if offset == 0:
output = ""
if output == "":
return ret_val(E_ERROR, "text does not match")
else:
return ret_val(E_OK, output)
# 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
def getTarget(listaCapitoli=None, titolo=None,nomeTarget="testoNs0.txt", lang="it"):
it=bot.Site(lang,"wikisource")
target=u""
if listaCapitoli==None:
if titolo!=None:
root=bot.Page(it,titolo).get()
root=root.replace("{{Testo","{{testo")
listaCapitoli=produci_lista(root,"{{testo|","}}",0)
for i in range(len(listaCapitoli)):
if "|" in listaCapitoli[i]:
listaCapitoli[i]=listaCapitoli[i].split("|")[0]
listaCapitoli[i]=titolo+listaCapitoli[i].strip()
print(listaCapitoli[i])
else:
print("Errore, necessario paramentro listaCapitoli o titolo")
return
monnezza=[[u"{{Qualità","}}"],["{{IncludiIntestazione","}}"],["{{Conteggio pagine","}}"],["<!-- Area dati:","<!-- a qui -->"]]
for capitolo in listaCapitoli:
testo=bot.Page(it,capitolo).get()
for m in monnezza:
x=find_stringa(testo,m[0],m[1],1)
if x!="":
testo=testo.replace(x,"")
target+=testo+"\n\n"
print(capitolo)
open(nomeTarget,"w", encoding="utf-8").write(target)
print("Salvato target in ",nomeTarget)
return
# utilities
# 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 go(fileTargetName, djvuName, startPageNumber, verbose=True, fileOutputName="output.txt", oldText=False):
## fileTargetName=os.path.join(folder,fileTargetName)
## djvuName=os.path.join(folder,djvuName)
## fileOutputName=os.path.join(folder,fileOutputName)
# estrazione testo djvu in lista di testi delle pagine
if djvuName.endswith(".djvu"):
pagine=extract_djvu_text(djvuName)
elif djvuName.endswith(".pdf"):
pagine=extract_pdf_text(djvuName)
else:
print("Errore: il file deve essere djvu o pdf")
return
# caricamento target
#target=unicode(open(fileTargetName).read(), "utf-8")
target=open(fileTargetName).read()
# do_match(target, cached_text, djvuname, number, verbose=True, prefix="Pagina", step=1):
result=do_match(target,pagine,djvuName,startPageNumber,verbose=verbose, oldText=oldText)
open(fileOutputName,"w", encoding="utf-8").write(result["text"])
print("Testo matched salvato in ",fileOutputName)