Cercare una stringa e rimpiazzare tutte le sue occorrenze

Probabilmente questa domanda è assai banale, ma da newby quale sono in
ruby, non riesco ad implementare cio che voglio.

Ho seguito qualche consiglio del forum e riesco ad aprire un documento e
a trascrivere quello che ho in un altro documento con questo codice da
voi consigliato:

file=open(‘tmp.txt’)
linee=file.readline
file.close
file2 = open(‘tmp2.txt’,‘w+’)
file2.puts linee
file2.close

Ora vorrei riuscire a fare una cosa piu complessa. Vorrei aprire il
file, cercare tutte le occorrenze (ad esempio di AUTOHR = {,} ) in un
file di questo tipo:

AUTHOR = {un_nome_qualunque, un_cognome_qualunque}
blablbalblalblabla
AUTHOR = {un_nome_qualunque1, un_cognome_qualunque1}
blablbalblalblabla
AUTHOR = {un_nome_qualunque2, un_cognome_qualunque2}
blablbalblalblabla

e trasformarlo in questo:

AUTHOR = {first => un_nome_qualunque, last => un_cognome_qualunque}
blablbalblalblabla
AUTHOR = {first => un_nome_qualunque1, last => un_cognome_qualunque1}
blablbalblalblabla
AUTHOR = {first => un_nome_qualunque2, last => un_cognome_qualunque2}
blablbalblalblabla

Dovrei forse usare qualcosa come linee.each_line ?
Spero che qualcuno possa aiutarmi. Grazie a tutti.

On 3/22/07, Livio M. [email protected] wrote:

Ora vorrei riuscire a fare una cosa piu complessa. Vorrei aprire il
file, cercare tutte le occorrenze (ad esempio di AUTOHR = {,} ) in un
file di questo tipo:

una piccola meta-domanda… stai per caso cercando di fare un sistema di
templating? perchè potresti riutilizzare erb

Chiaro Scuro wrote:

On 3/22/07, Livio M. [email protected] wrote:

Ora vorrei riuscire a fare una cosa piu complessa. Vorrei aprire il
file, cercare tutte le occorrenze (ad esempio di AUTOHR = {,} ) in un
file di questo tipo:

una piccola meta-domanda… stai per caso cercando di fare un sistema di
templating? perch� potresti riutilizzare erb

ciao,
il template esiste già in teoria, ed è basato su quello che viene
chiamato fondamentalmente bibtex. un file .bib, bibtex è del tipo

@Book{abramowitz+stegun,
author = “Milton Abramowitz”,
title = “Handbook of Mathematical Functions with
Formulas, Graphs, and Mathematical Tables”
}

io vorrei riuscire a rimpiazzare l’occorrenza ad esempio dell’autore
cosi:

@Book{abramowitz+stegun,
author = “first => Milton last => Abramowitz”,
title = “Handbook of Mathematical Functions with
Formulas, Graphs, and Mathematical Tables”
}

non so cosa sia erb, ma sono veramente ai primi passi con ruby e questo
esempio mi servirebbe per capirne il suo funzionamento.

giovedi 22 marzo 2007, alle 11:33, il navigatore Livio M. scrisse:

e trasformarlo in questo:

AUTHOR = {first => un_nome_qualunque, last => un_cognome_qualunque}
blablbalblalblabla
AUTHOR = {first => un_nome_qualunque1, last => un_cognome_qualunque1}
blablbalblalblabla
AUTHOR = {first => un_nome_qualunque2, last => un_cognome_qualunque2}
blablbalblalblabla

output = ‘’
File.open(‘input’).each_line do | line |
output << line.gsub(
/^([^}]+){([^,]+), ([^}]+)}(\s+)$/,
‘\1{first => \2, last => \3}\4’
)
end

input = nome del file in ingresso
output = stringa che contiene il risultato

Gabriele L. wrote:

giovedi 22 marzo 2007, alle 11:33, il navigatore Livio M. scrisse:

e trasformarlo in questo:

AUTHOR = {first => un_nome_qualunque, last => un_cognome_qualunque}
blablbalblalblabla
AUTHOR = {first => un_nome_qualunque1, last => un_cognome_qualunque1}
blablbalblalblabla
AUTHOR = {first => un_nome_qualunque2, last => un_cognome_qualunque2}
blablbalblalblabla

output = ‘’
File.open(‘input’).each_line do | line |
output << line.gsub(
/^([^}]+){([^,]+), ([^}]+)}(\s+)$/,
‘\1{first => \2, last => \3}\4’
)
end

input = nome del file in ingresso
output = stringa che contiene il risultato

grazie per il tuo aiuto. l’espressione regolare cosi concepita mi
permette, mi pare di aver capito, di rimpiazzare ogni occorrenza del
tipo

PAROLA = {nome, cognome}

con

PAROLA = {first => nome, last => cognome}

il problema è che con un’entrata di questo tipo non otterrei il
risultato voluto:

@Book{abramowitz+stegun,
author = “Milton Abramowitz”,
title = “Handbook of Mathematical Functions with
Formulas, Graphs, and Mathematical Tables”
}

dovrei specificargli effettivamente che stiamo parlando di una riga che
comincia proprio con AUTHOR o author. posso aggiungere AUTHOR
direttamene nell’espressione regolare ?

grazie per il tuo aiuto. l’espressione regolare cosi concepita mi
permette, mi pare di aver capito, di rimpiazzare ogni occorrenza del
tipo

PAROLA = {nome, cognome}

con

PAROLA = {first => nome, last => cognome}

il problema è che con un’entrata di questo tipo non otterrei il
risultato voluto:

@Book{abramowitz+stegun,
author = “Milton Abramowitz”,
title = “Handbook of Mathematical Functions with
Formulas, Graphs, and Mathematical Tables”
}

dovrei specificargli effettivamente che stiamo parlando di una riga che
comincia proprio con AUTHOR o author. posso aggiungere AUTHOR
direttamene nell’espressione regolare ?

Ok, mi rispondo da solo…la mia è solo ignoranza nella conoscenza delle
espressioni regolari, che in ruby si rivelano davvero potentissime
(bello!). Credo sia cosi la regexp:

/^AUTHOR([^}]+)\{([^,]+), ([^}]+)\}(\s+)$/,

‘AUTHOR = {first => \2, last => \3}\4’)

Grazie.

ho ancora un problema che non riesco a risolvere correttamente:
ammettendo ora di avere più sostituzioni da fare dello stesso tipo
(magari AUTHOR ed EDITOR), se uso sempre lo stesso output il file
sovrascriverà due volte. output dovrebbe essere preso in esame come
fosse un buffer credo…e dunque dovrei analizzare l’uscita in stringa
per ripassarla in analisi.

output = ‘’
output2 = ‘’
File.open(‘tmp.txt’).each_line do | line |
output << line.gsub(
/^ *author *([^}]+){([^,]+) ([^}]+)},(\s+)$/i,
‘AUTHOR = {first => \2, last => \3},\4’)
string.output.each_line do | line | ## credo proprio nn sia corretta,
ma posto il principio
output2 << line.gsub(
/^ *editor *([^}]+){([^,]+) ([^}]+)},(\s+)$/i,
‘EDITOR = {first => \2, last => \3},\4’)
file2 = open(‘tmp2.txt’,‘w+’)
file2.puts output2
file2.close
end

cioe dovrei riuscire ad applicare il gsub all’output della prima
sostituzione tirandone fuori un output2. dovrebbe essere cosi. la mia
domanda é: posso applicare each_line ad output?

grazie ancora per la pazienza.

giovedi 22 marzo 2007, alle 15:12, il navigatore Livio M. scrisse:

output << line.gsub(
end
Mooolto piu’ semplice

output = ‘’
File.open(‘input’).each_line do | line |
line = line.gsub(
/^author = {([^,]+), ([^}]+)}(\s+)$/,
‘AUTHOR = {first => \1, last => \2}\3’
)
line = line.gsub(
/^editor = {([^,]+), ([^}]+)}(\s+)$/,
‘EDITOR = {first => \1, last => \2}\3’
)
output << line
end

Ovvero usi line come variabile temporanea per mantenere il risultato
intermedio linea per linea e poi solo alla fine aggiungi la linea al
risultato (che poi aggiungerai ad un file)

NOTA: se ho capito bene, la differenza fra le varie sostituzioni e’
solo la parola all’inizio della linea, che nel file originale e’ in
minuscolo e dopo la sostituzione e’ in maiuscolo, se e’ cosi’, la
soluzione e’ ancora piu’ semplice, te la cavi con una sola espressione

output = ‘’
File.open(‘input’).each_line do | line |
output << line.gsub(/^([^}]+){([^,]+), ([^}]+)}(\s+)$/) do
“#{$1.upcase}{first => #{$2}, last => #{$3}}#{$4}”
end
end

gsub accetta anche un blocco come parametro, al quale passa tutto il
match (nel nostro caso tutta la linea), a noi questo non interessa,
interessano i submatch (indicati dalle parentesi tonde
nell’espressione regolare), ci va bene perche’ ruby per ogni
esecuzione di un’espressione regolare valorizza le variabili globali
$1, $2, $3, … che corrispondono (nella versione originale del mio
codice) a \1, \2, \3, … solo che sono variabili e quindi possiamo
farci quello che vogliamo, come per esempio trasformare il primo
submatch ($1) in upper case


Gabriele L.
contact me at info at gabrielelana dot it
http://www.gabrielelana.it - Agile methodologies and Programming
http://www.xpug.it - italian eXtreme Programming User Groups

NOTA: se ho capito bene, la differenza fra le varie sostituzioni e’
solo la parola all’inizio della linea, che nel file originale e’ in
minuscolo e dopo la sostituzione e’ in maiuscolo, se e’ cosi’, la
soluzione e’ ancora piu’ semplice, te la cavi con una sola espressione

output = ‘’
File.open(‘input’).each_line do | line |
output << line.gsub(/^([^}]+){([^,]+), ([^}]+)}(\s+)$/) do
“#{$1.upcase}{first => #{$2}, last => #{$3}}#{$4}”
end
end

gsub accetta anche un blocco come parametro, al quale passa tutto il
match (nel nostro caso tutta la linea), a noi questo non interessa,
interessano i submatch (indicati dalle parentesi tonde
nell’espressione regolare), ci va bene perche’ ruby per ogni
esecuzione di un’espressione regolare valorizza le variabili globali
$1, $2, $3, … che corrispondono (nella versione originale del mio
codice) a \1, \2, \3, … solo che sono variabili e quindi possiamo
farci quello che vogliamo, come per esempio trasformare il primo
submatch ($1) in upper case

Ti ringrazio tantissimo per il tuo aiuto.
Per quel che riguarda la conversione:

L’obbiettivo è quello di passare da una entry come questa (ce ne possono
essere parecchie in un documento):

@BOOK{leclerc1976,
AUTHOR = {Jean Herverie},
TITLE = {{Ergad} le composite},
EDITOR = {Jean Tchoe},
NUMBER = 12,
SERIES = {N’{e}bula},
PUBLISHER = {’{E}ditions Opta},
YEAR = 1976}

a questa:

@BOOK{leclerc1976,
AUTHOR = {first => Jean, last => Herverie},
TITLE = {{Ergad} le composite},
EDITOR = {first => Jean, last => Tchoe},
NUMBER = 12,
SERIES = {N’{e}bula},
PUBLISHER = {’{E}ditions Opta},
YEAR = 1976,
LANGUAGE = french}

Praticamente la mia espressione regolare non deve essere case sensitive
(almeno nei campi AUTHOR ed EDITOR), quindi poco importa. L’importante è
formattare correttamente il nome.
Altra differenza tra le due entry è il fatto che nella prima manca il
campo LANGUAGE. In questo caso dovrei chiedere all’utente una cosa del
tipo "Quale lingua vuoi usare nella entry con autore AUTHOR ed editore
EDITOR ? ". A quel punto riprendo lo standard input e aggiungo il campo
language alla fine.

Marco Dalla S. wrote:

Il 22/03/07, Livio M. [email protected] ha scritto:

Salve a tutti, sono un nuovo acquisto e vengo dal Perl. (kral, per chi
magari bazzica Perl.it).

Praticamente la mia espressione regolare non deve essere case sensitive

(almeno nei campi AUTHOR ed EDITOR), quindi poco importa. L’importante �
formattare correttamente il nome.

Non entro nel merito del codice, visto che ancora non conosco bene il
linguaggio, ma mi viene un dubbio: nei nomi composti da pi� di due parole,
come identifichi il nome e il cognome?
Ad esempio, io mi chiamo Marco Dalla S., dovrebbe essere AUTHOR =
{first
=> Marco, last => Dalla S.}.
Ma nel caso di Vittorio Emanuele di Savoia (scusate, � il primo che mi �
venuto in mente) come risolvi?

/me curioso e alle prime armi.

Saluti,

beh, in teoria dovrebbe fare comportarsi cosi:

{first => Marco, von => Dalla last => Stella}

ma sono ancora troppo alle prime armi, forse, per arrivare a questo?

in ogni caso si, dovrebbe essere qualcosa che dovrei decidere insieme
all’utente. cioé quando incontra un nome di questo tipo, lo script
dovrebbe accorgersene e chiedere all’utente se la sua traduzione é
giusta. ma non son ancora come fare questo.

Il 22/03/07, Livio M. [email protected] ha scritto:

Salve a tutti, sono un nuovo acquisto e vengo dal Perl. (kral, per chi
magari bazzica Perl.it).

Praticamente la mia espressione regolare non deve essere case sensitive

(almeno nei campi AUTHOR ed EDITOR), quindi poco importa. L’importante è
formattare correttamente il nome.

Non entro nel merito del codice, visto che ancora non conosco bene il
linguaggio, ma mi viene un dubbio: nei nomi composti da più di due parole,
come identifichi il nome e il cognome?
Ad esempio, io mi chiamo Marco Dalla S., dovrebbe essere AUTHOR =
{first
=> Marco, last => Dalla S.}.
Ma nel caso di Vittorio Emanuele di Savoia (scusate, è il primo che mi è
venuto in mente) come risolvi?

/me curioso e alle prime armi.

Saluti,

Cosa crea il file di bibtex? Forse i cognomi di tipo “Dalla S.” o
“von Rosen” saranno già formattato come Marco {Della Stella}.

Il 23/03/07, Rob C. [email protected] ha scritto:

Cosa crea il file di bibtex? Forse i cognomi di tipo “Dalla S.” o
“von Rosen” saranno già formattato come Marco {Della Stella}.

Dando un occhiata alla descrizione di Bibtex della wikipedia [1],
l’autore dovrebbe essere formattato
così:
author = “von Hicks, III, Michael”

Quindi Cognome, suffissi (come jr., sr. o III) e nome.

[1] http://en.wikipedia.org/wiki/BibTeX#Author_formatting

Il 23/03/07, Rob C.[email protected] ha scritto:

Sì, ho dovuto mettere quel link. Sotto c’è scritto:

“L’autore può non usare una virgola per separare il suffisso del nome
dal cognome, usando invece parentesi graffe come in {Hicks III}.”

Ops… non avevo letto tutto! Sorry, hai ragione tu! :slight_smile:

Sì, ho dovuto mettere quel link. Sotto c’è scritto:

“L’autore può non usare una virgola per separare il suffisso del nome
dal cognome, usando invece parentesi graffe come in {Hicks III}.”

Allora depende cosa usa il software che genera i file di bibtex.

Marco Dalla S. wrote:

Il 23/03/07, Rob C.[email protected] ha scritto:

S�, ho dovuto mettere quel link. Sotto c’� scritto:

“L’autore pu� non usare una virgola per separare il suffisso del nome
dal cognome, usando invece parentesi graffe come in {Hicks III}.”

Ops… non avevo letto tutto! Sorry, hai ragione tu! :slight_smile:

Dunque, quella vista da voi è la sintassi di BibTeX. Io sto studiando
una nuova implementazione di BibTeX che possa permettermi di rendere più
chiara e meno ridondante la sintassi Bib. Lo standard da me voluto è
quello che potete vedere con l’uso delle parole chiave first / last per
identificare nome e cognome.

Come potete vedere BibTeX usa parecchi giri sintattici per scrivere un
nome. L’obbiettivo é proprio quello di “pulire” la sintassi usando ad
esempo

first => Olivio, last => Mariano.

Non ho la doc sotto mano, ma appena posso posto un po piu di
informazioni.

venerdi 23 marzo 2007, alle 13:16, il navigatore Livio M. scrisse:

e la cambio con questa in gsub ‘LANGUAGE = {english} \3’

per avere questo


pages = {1–16},
crossref = {TPHOLs96}
LANGUAGE = {english}}

solo che l’uso della variabile \3 mi sembra inopportuno.

infatti :slight_smile:

\1 fa riferimento al primo submatch, ovvero alla parte di testo che
viene “catturata” dall’espresione regolare all’interno della prima
coppia di parentesi tonde

\2 … della seconda coppia di parentesi tonde
\3 … della terza coppia di parentesi tonde
ecc…

quindi se la tua espressione regolare e’

/^([]*}) *[}]/i$

al limite avresti a disposizione solo \1, comunque anche l’espressione
non mi sembra molto corretta… prova con

/^([^}]+})}$/ da sostituire con “\1\n\tLANGUAGE = {english}}”

vediamo di capire insieme l’espressione regolare (perche’ mi sembra
che ci sia un po’ di confusione)

^ = asserisco di essere all’inizio della stringa
( = inizia qualcosa che mi interessa e che voglio ricordare
[^}]+} = qualsiasi cosa che non sia il carattere ‘}’ ripetuto
1 o + volte seguito dal carattere ‘}’
) = fine della parte interessante
} = il carattere ‘}’
$ = asserisco di essere alla fine della stringa

quindi consumi tutti i caratteri dall’inizio della stringa fino alla
prima parentesi graffa chiusa compresa, e asserisci che dopo ci deve
essere un’altra parentesi graffa chiusa e poi la fine della stringa.
quello che sta fra l’inizio della stringa e la prima parentesi graffa
chiusa compresa (essendo fra parentesi tonde = submatch), te lo
ritroverai disponibile all’interno della stringa di sostituzione come
\1

quindi la stringa di sostituzione sara’

“\1\n\tLANGUAGE = {english}}”

\1 = \1 viene preceduto da un altro \ perche’ fra doppi apici il
il carattere ‘’ viene considerato carattere di escape
\n\t = sono per la formattazione

grazie per la spiegazione ben fatta sul significato preciso delle
espressioni regolari.

per chi mi chiedeva come formattare i nomi compositi eccovi un esempio:
la entry appare così:

(1) AUTHOR = {Marco Dalla S.}

e deve essere tradotta cosi:

(2) AUTHOR = {first => Marco, von => Dalla, last => Stella}

o nel caso, ad esempio di una entry cosi:

(3) AUTHOR = {Marco Stella with Paolo Rossi}

deve essere tradotta cosi:

(4) AUTHOR = {first => Marco, last => Stella, with first => Paolo,
last => Rossi}

von è dunque una parola chiave come first e last. with è una sintassi
usata da bibtex per connettere gli autori e dunque è anch’essa una
parola chiave.

non so se ci sia modo di uscirsene con un’espressione regolare. in
teoria sarebbe il caso di imbastire un costrutto condizionale in ruby
tale che se trova tre particelle come in (1) nel nome dell’autore allora
deve formattare come in (2). se trova un with come terza particella (3)
deve formattare come in (4).

Domandona ancora: volendo cercare una fine di una entry dovrei cercare
una doppia parentesi graffa. Questo mi servirebbe per introdurre tra le
due il campo language prima che la entry finisca.

Ad esempio, alla fine della entry:


pages = {1–16},
crossref = {TPHOLs96}}

cerco la doppia parentesi graffa, credo cosi:

/^([]*}) *[}]/i$

e la cambio con questa in gsub ‘LANGUAGE = {english} \3’

per avere questo


pages = {1–16},
crossref = {TPHOLs96}
LANGUAGE = {english}}

solo che l’uso della variabile \3 mi sembra inopportuno.

In questo momento sto lavorando con lo standard input e standard output.
Vorrei capire una cosa: posso interagire con l’utente tramite dei
printf, stdin ecc ecc prima del gsub di ruby ?

In pratica posso fare una cosa del genere ?
Cioé prima della sostituzione gsub chiedere all’utente quale lingua
voler immettere del tipo:

puts ‘Quale lingua ?’
lingua = gets
puts 'la lingua voluta e ’ + lingua + ‘’
line = line.gsub(
/^([^}]+})}$/,
“\1,\nLANGUAGE = {+ lingua +}}”)
output << line

Come é ora il codice passa e non dice niente in console. Sbaglio
probabilmente nell’uso del puts (un printf sarebbe piu appropriato -
sempre che esista in ruby) e del gets. grazie in anticipo.