Newsgroup: it.comp.lang.javascript
Titolo: Script molto lento.

E questo si nota sopratutto con FF3.
Per funzionare, funziona, ma perch� lo fa cos� lentamente?
Copy&paste:
<html><head>
<script type="text/javascript">
function changeFont() {
 var cod="0";
 var val=document.getElementById("txr").value;
 for (var text="",i=0;i<val.length;i++) {
 chr=val.charAt(i);
 if (chr=="\u00ab"){
 if (cod=="1") chr="\u00bb";
 cod=="1"?cod="0":cod="1";
 }
 text+=chr;
 document.getElementById("txr").value=text;
}}
</script>
</head>
<body onload="document.getElementById('txr').focus();">
<h4>Si deve sostituire il secondo carattere di una coppia identica, che racchiude del testo.<br/>
In questo caso "�testo�" con "�testo�". Copy&Paste:</h4>
Se la situazione �� particolarmente grave,� dopo visita neurologica,<br/>
�si ricorre� all'intervento chirurgico �in endoscopia� previa<br/>
visita neurologica �e relativa� risonanza magnetica nucleare. �</br>
La terapia� farmacologica, �che consiste nell'assunzione� di anti<br/>
infiammatori, �� comunque� palliativa �perch� i modi per risolvere<br/>
la situazione� meno cruenti �sono dimagrire e fare� molto<br/>
nuoto o anche delle �belle passeggiate.�<br/><br/>
<form>
<textarea wrap="off" cols="80" rows="20" id="txr"></textarea><br>
<input onclick="changeFont();" type="button" value="replace" />
<input type="reset" onclick="document.getElementById('txr').focus();" value="clear" />
</form>
</body></html>
-- 
    * b *
  *   y   *
*   Piero   *
#v+
-rebus sic stantibus-
#v-
 

  document.getElementById("txr").value=text;
La prima cosa che mi salta all'occhio e' che esegui questa riga a ogni 
ciclo (mentre basterebbe farlo alla fine).
In parole povere per ogni carattere recuperi un riferimento alla 
textarea e ne riscrivi il valore.
Ad ogni modo perche' non hai pensato ad un approccio con le espressioni 
regolari?

   for (var text="",i=0;i<val.length;i++) {
for (var i=0, chr; i < len; i++) {
	chr = val.charAt(i);
	if (chr == ab) {
		if (cod) chr = bb;
		cod = !cod;	
	}
	text += chr;
}
txr.value = text;
Giusto per mio diletto, se ti capita di testare lo script, mi puoi
dire se con quest'altro codice noti differenze (in termini, ovvio,
di performance):
var txr = document.getElementById("txr");
var val = txr.value.split("");
var len = val.length;
var ab = "\u00ab";
var bb = "\u00bb";
var cod = false;
for (var i=0; i < len; i++) {
	if (val[i] == ab) {
		if (cod) val[i] = bb;
		cod = !cod;	
	}
}
txr.value = val.join("");
N.B.
Considera che sono un po' rintronato stasera, non assicuro che nel
codice non vi sia qualche boiata. ;)
-- 
"When you have eliminated the impossible, whatever remains, however
improbable, must be the truth."

 espressioni regolari?
Si l'ho fatta, ma non mi soddisfa, perch�, come puoi vedere, si limita
a sistemare un max di due coppie �testo� per riga (aumentandole la regexp
diventa complicatissima) e poi, chiss� perch�, non funziona con IE e FF,
ma non con Opera. :-?
Questo � il codice:
<html><head>
<script type="text/javascript">
function changeFont() {
txt=document.getElementById("txr").value.replace(/(.*)\u00AB(.*\u00AB.*\u00AB.*)/g,"$1\u00AB\u0081\n$2").replace(/(.*\u00AB.*)\u00AB/g,"$1\u00BB").replace(/(.*\u00AB.*)\u00AB(.*\u00AB.*\u00BB)/g,"$1\u00BB$2").replace(/(.*\u00AB[\w,\s-]*)\n/g,"$1\u007F").replace(/(\u00AB.*\u007F.*)\u00AB/g,"$1\u00BB").replace(/\u007F/g,"\n").replace(/\r/g,"").replace(/\u0081\n/g,"");
document.getElementById("txr").value=txt;
}
</script>
</head>
<body onload="document.getElementById('txr').focus();">
<h4>Sostituisce con "�" la seconda "�" che chiude il testo. Supporta un massimo di due ricorrenze nella stessa riga.<br/>Lo f� anche se la frase viene spezzata a fine riga, nei limiti dell'esempio. Copy&paste:</h4>Se la situazione �� particolarmente grave,� dopo visita neurologica, <br/>
�si ricorre� all'intervento chirurgico �in endoscopia� previa <br/>
visita neurologica e relativa �risonanza magnetica nucleare.� <br/>
La terapia farmacologica, che consiste nell'assunzione �di anti <br/>
infiammatori,� � comunque �palliativa� perch� i modi per risolvere <br/>
la situazione meno cruenti �sono dimagrire<br/>
� e fare �molto nuoto o anche delle belle passeggiate.�
<form>
<textarea id="txr" rows="20" wrap="off" cols="100"></textarea>
<br/>
<input onclick="changeFont();" type="button" value="replace"/>
<input type="reset" onclick="document.getElementById('txr').focus();" value="clear"/>
</form>
</body></html>
-- 
    * b *
  *   y   *
*   Piero   *
#v+
M'hanno regalato un libro, ma si sono dimenticati del software.
#v-

 di performance):
Prima di tutto grazie. :-)
Stasera non ho tempo, ma appena posso provo.
    ...skipped!
-- 
    * b *
  *   y   *
*   Piero   *
#v+
-beati monocoli in terra caecorum-
#v-

 IE e FF, ma non con Opera. :-?
C'� un *non* di troppo, mi correggo:
regexp diventa complicatissima) e poi, chiss� perch�, *funziona* con
IE e FF, ma non con Opera. :-?
    ...skipped!
-- 
    * b *
  *   y   *
*   Piero   *
#v+
Alzhaimer e... cammina.
#v-
 

 codice non vi sia qualche boiata. ;)
Nessun errore, va alla grande, ad occhio sembra un /pelino/ pi� veloce
dell'altro, per� considera che il tutto dura una frazione di secondo pur
avendo aumentato il testo di 20 volte per poterlo valutare.
Thanks. :-)
-- 
    * b *
  *   y   *
*   Piero   *
#v+
Alzhaimer e... cammina.
#v-

 chiss� perch�, *funziona* con IE e FF, ma non con Opera. :-?
Risolto, adesso funziona anche con Opera.
Ho aggiunto questo replace: .replace(/\r/g,"")
prima di questo: .replace(/(.*\u00AB[\w,\s-]*)\n/g,"$1\u007F")
-- 
    * b *
  *   y   *
*   Piero   *
#v+
-errare humanum est-
#v-

 prima di questo: .replace(/(.*\u00AB[\w,\s-]*)\n/g,"$1\u007F")
Ma perche' tutta questa catena di "replace"?
Ti butto li' la prima cosa che mi e' venuta in mente, non 
necessariamente la migliore:
var o = document.getElementById("txr"),
         chars = "\u00ab\(\[\{\u00bb)]}",
         re = new RegExp("([" + chars.substr(0, chars.length >> 1) + 
"])([\\w\\s�����,;:\\.]+)\\1", "gi");
     o.value = o.value.replace(re, function($1, $2, $3){
         return $2 + $3 + chars.charAt(chars.indexOf($2) + (chars.length 
 >> 1));
     });
In chars memorizzi tutti i caratteri che rappresentano le "aperture", 
con l'escape dove necessario visto che vanno in una regexp, seguiti 
nello stesso ordine da quelli che rappresentano le "chiusure".
Il codice qui sopra e' ovviamente solo un'idea per affrontare la 
questione in una logica differente.

 questione in una logica differente.
A questo proposito potresti voler aggiungere l'apostrofo alla regexp, 
visto che me lo son proprio dimenticato...

Andrea Scartabelli wrote:
[...]
...visto che di lavorare oggi non ne ho proprio voglia, te l'ho 
riscritta in maniera un poco piu' pulita:
var o = document.getElementById("txr"),
         chars = "\u00ab\(\[\{\u00bb)]}",
         md = chars.length >> 1,
         m = chars.substr(0, md),
         re = new RegExp("([" + m + "])([^" + m + "]+)\\1", "gi");
o.value = o.value.replace(re, function($1, $2, $3){
	return $2 + $3 + chars.charAt(chars.indexOf($2) + md);
});

 Mai visto, comunque ho provato, ma d� errore.
Mi auguro che una variabile numerica o booleana tu l'abbia gi� vista. :)
E sicuramente non ti da errore scrivere tale assegnazione.
Il punto � che tu usi cod come se fosse un numero sebbene ogni volta gli
passi un valore stringa:
	cod=="1"?cod="0":cod="1";
Quindi potresti trasformarlo in numero:
	cod==1?cod=0:cod=1;
Ma anche quando l'hai trasformato in numero lo stai usando come fosse un
booleano, quindi tanto vale:
	cod==true?cod=false:cod=true;
che equivale a:
	cod=!cod;


 questione in una logica differente.
E tu credi che sarei capace di scrivere uno script come hai postato? :-D
-- 
    * b *
  *   y   *
*   Piero   *
#v+
� un genio della scrittura, ha inventato il paragrafo senza fili.
#v-

"Andrea Scartabelli" [by Thunderbird 2.0.0.23 (Windows/20090812)] on



Mi hai fatto conoscere un modo, per me nuovo, di utilizzare le regexp.
Intanto ti ringrazio e mi salvo il messaggio, poi prover� a studiarlo,
ma credo che non riuscir� a capirlo del tutto.
Per il momento ho capito che lo script posso ridurlo cos�:
var o = document.getElementById("txr"),
         chars = "\u00ab(\u00bb)",
         md = chars.length >> 1,
         m = chars.substr(0, md),
         re = new RegExp("([" + m + "])([^" + m + "]+)\\1", "g");
o.value = o.value.replace(re, function($1, $2, $3){
return $2 + $3 + chars.charAt(chars.indexOf($2) + md);
});
ma questa riga non la capisco, e per favore, dovresti spiegarmela:
md = chars.length >> 1,
e poi perch� 2 ">"?
-- 
    * b *
  *   y   *
*   Piero   *
#v+
-ad audiendum verbum-
#v-

  cod=!cod;
Capito tutto :-) grazie.
-- 
    * b *
  *   y   *
*   Piero   *
#v+
-deus ex machina-
#v-

 e poi perch� 2 ">"?
Per spiegazione approfondita vedi:
https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Operators/Bitwise_Operators
Provo a spiegare in due parole.
Innanzitutto qui l'ho scritto solo per abitudine, e andava benissimo 
scrivere "chars.length / 2", in questo caso equivalente.
Mi spiego con un esempio.
Il doppio maggiore (esiste anche il triplo, vedi la reference) e il 
doppio minore sono dei "bitwise shift operators".
Prendiamo il numero cinque, che in binario diventa 101.
Lo "shift sinistro" (doppio minore) di una posizione prevede di spostare 
tutti i bit verso sinistra inserendo uno zero a destra:
0101 (il nostro cinque decimale)
1010 (i bit spostati di una posizione a sinistra)
In javascript: 5 << 1.
Facendo un rapido calcolo puoi vedere che spostare i bit a sinistra di 
una posizione equivale a una moltiplicazione per due.
Quindi: 5 << 1 e' uguale a 10, 5 << 2 e' uguale a 20, ecc.
Lo "shift destro", quello che ho usato nello script e' l'operazione 
contraria. Ovvero i bit vengono spostati verso destra scartando pero' i 
bit in eccesso.
Quindi:
101 (sempre il nostro cinque)
010 (i bit spostati di una posizione a destra)
Spostare i bit a destra di una posizione e' quindi equivalente a una 
divisione per due ma scartando il resto: 5 >> 1 e' uguale a due, 5 >> 2 
e' uguale a uno.
Ininfluente nel caso del mio script, ma le operazioni a livello di bit 
sono piu' veloci.
Spero di essere stato sufficientemente chiaro.

 Spero di essere stato sufficientemente chiaro.
'azz... chiarissimo, di pi� non potevi, ti ringrazio. :-)
-- 
    * b *
  *   y   *
*   Piero   *
#v+
Guardo il cielo e sorrido, spero in una foto satellitare.
#v-

 di performance):
Se ti interessano le performance, anche per mia curiosit�, cronometro
alla mano, ho testato i vari script con un file di testo di 101KB:
                           con FF3   con Opera   con IE8
la mia semplice regexp     3"        2",2        7",8
il mio script              1"        1"          5",6
il tuo 1� script           1"        0",8        5",4
il tuo 2� (join)           1"        0",9        5",5
lo scrip di Andrea         1"        0",9        7",2
Questo � il tempo riscontrato, salvo un decimo di secondo +o- nello
schiacciare il pulsante del cronometro.
Come vedi il pi� lento � IE8, e che la semplice regexp, in questo caso,
si rivela perdente con tutti i browser.
    ...skipped!
-- 
    * b *
  *   y   *
*   Piero   *
#v+
-panem et circenses-
#v-

 si rivela perdente con tutti i browser.
Scusa, ma mi sembra parecchio strano.
La regexp dovrebbe essere sempre piu' veloce e anzi, facendo un rapido 
test la differenza piu' grossa si vede proprio con ie8 (e la minore con 
firefox). A maggior ragione aumentando la quantita' di testo.
La cosa che mi pare piu' strana in assoluto e' che hai addirittura delle 
misure in secondi...
Mi puoi mandare i file che hai usato per test (dicendomi anche per 
curiosita' su che pc hai provato)?
Vorrei provare a ripeterli per capire.

 Vorrei provare a ripeterli per capire.
L'indirizzo � valido o devo eliminare BRUNO?
Dimenticavo: Opera 10
PC datato: P4 CPU 1,70 GHz 512MB RAM XP HE SP3
-- 
    * b *
  *   y   *
*   Piero   *
#v+
Alzhaimer e... cammina.
#v-

 L'indirizzo � valido o devo eliminare BRUNO?
Urca, non mi ero accorto di avere ancora quell'indirizzo nel newsgroup...
Manda a il mio nome punto il mio cognome, sulla mail di google.
Grazie

 Grazie
A te!
:-)
OK, il file .txt di 104.400 byte te lo mando di 894 byte zippato al 99%.
-- 
    * b *
  *   y   *
*   Piero   *
#v+
Assolto perch� il fatto non costituisce dibattito.
#v-

 OK, il file .txt di 104.400 byte te lo mando di 894 byte zippato al 99%.
Intendevo gli script usati per fare i test, ma poco importa.
Ti confermo che la regexp e' SEMPRE piu' veloce anche coi tuoi 100Kb di 
testo.
Firefox e' quello dove la differenza si vede meno, solo poco piu' del 
doppio piu' veloce nei miei test, negli altri puo' arrivare a quasi 
dieci volte.
Errori presumibili che hai fatto nei tuoi test leggendo quel che scrivevi:
1) misura col cronometro (MISURA COL CRONOMETRO?)
dovresti creare una data prima dell'esecuzione dell'operazione, una alla 
fine e fare la differenza. Ripetere questo un po' di volte e fare una media.
2) non includere nei test la lettura e la scrittura del valore nella 
textarea, altrimenti aggiungi all'errore precedente altri fattori tra i 
quali la velocita' di rendering a video diversa tra i vari browser.
Anche facendo l'errore "due", ho provato, le regexp mi risultano sempre 
piu' veloci su tutti i browser. E non di poco.

 sempre piu' veloci su tutti i browser. E non di poco.
Non me ne volere, ma non ho la minima idea di come procedere e ho poco
interesse ad impararlo. Son per� curioso di conoscere il risultato dei
tuoi test.
-- 
    * b *
  *   y   *
*   Piero   *
#v+
-do ut des-
#v-

 tuoi test.
Scusa il ritardo, ma sono stato un po' preso da altro.
Ecco i miei risultati, qualche considerazione e gli script usati.
I test sono stati fatti su Win XP SP3, Athlon 64 3200+ con 2,5 Gb di 
RAM, i risultati sono la media aritmetica dei tempi di esecuzione, 
ovviamente in millisecondi, dei test ripetuti consecutivamente per 500 
volte.
Il testo usato e' quello che mi hai fornito di 104400 byte.
La funzione del test "regexp", a differenza delle altre, sostituisce 
piu' caratteri e non solo gli "\u00ab".
Diventerebbe piu' veloce sostituendo un solo carattere perche' non e' 
piu' necessario usare una funzione di callback.
Si potrebbe eliminare la callback anche mantenendo la sostituzione 
multipla, ma per fare tutto in un unico replace l'unico modo che mi e' 
venuto in mente e' usare la proprieta' statica "RegExp.$1", ora 
considerata deprecata.
Ad ogni modo ancora funziona e ho verificato che in certi browser il 
guadagno e' notevole rispetto alla callback.
Zer0 ha detto che, tempo permettendo, avrebbe verificato un altro modo 
di fare un unico replace e sostituire caratteri multipli senza la callback.
Il test "join" e' la funzione che separa i caratteri mettendoli in un 
array e facendo un join alla fine.
Il test "conc." e' la funzione che usa l'operatore "+=" sulla stringa.
Caso curioso e' Safari su windows: la regexp e il join sono praticamente 
equivalenti.
Zer0 ha fatto un test su mac e mi dice che Safari raggiunge nella regexp 
la velocita' di Chrome su windows.
Risultati:
Firefox 3.5.3
---------------
regexp:  11.612
join:    51.768
conc.:   18.856
IE 8
---------------
regexp:  15.500
join:   125.062
conc.:  308.046
Opera 10
---------------
regexp:  19.176
join:   169.530
conc.:  149.590
Safari 4.0.3
---------------
regexp:  14.112
join:    14.398
conc.:   25.296
Chrome 3.0.195
---------------
regexp:   4.262
join:    47.012
conc.:   25.804
Per chi vuole divertirsi a ripetere il test, due righe di html:
<input type="text" id="result" /><br />
<input onclick="doMultipleTests(fRegExp, 500)" type="button" value="Test 
con regexp" /><br />
<input onclick="doMultipleTests(fStandardWJOIN, 500)" type="button" 
value="Test con ciclo caratteri e join" /><br />
<input onclick="doMultipleTests(fStandardNOJOIN, 500)" type="button" 
value="Test con ciclo caratteri e accodamento stringa" />
e lo script:
function fStandardNOJOIN(){
     var text = "",
         len = sText.length,
         ab = "\u00ab",
         bb = "\u00bb",
         cod = false;
     for(var i = 0, chr; i < len; i++){
         chr = sText.charAt(i);
         if(chr == ab){
             if(cod) chr = bb;
             cod = !cod;
         }
         text += chr;
     }
}
function fStandardWJOIN(){
     var val = sText.split(""),
         len = val.length,
         ab = "\u00ab",
         bb = "\u00bb",
         cod = false;
     for(var i = 0; i < len; i++)
         if(val[i] == ab) {
             if(cod) val[i] = bb;
             cod = !cod;
         }
     var sFinal = val.join("");
}
function fRegExp(s){
     var chars = "\u00ab([{\u00bb)]}",
         md = chars.length >> 1,
         m = chars.substr(0, md),
         re = new RegExp("([" + m + "])([^" + m + "]+)\\1", "g");
     var sFinal = sText.replace(re, function($1, $2, $3){
         return $2 + $3 + chars.charAt(chars.indexOf($2) + md);
     });
}
function doSingleTest(f){
     var a = new Date();
     f();
     var b = new Date();
     return b - a;
}
function doMultipleTests(f, n){
     var totalTime = 0,
         toBeExecuted = n;
     (function(){
         if(toBeExecuted--){
             totalTime += doSingleTest(f);
             setTimeout(arguments.callee, 1);
         }else
             document.getElementById("result").value = "media: " + 
(totalTime / n) + " ms";
     })();
}
var sText = "<qui ripetete il testo del primo post di P/ero fino a 
raggiungere 104400 byte>";
Ti mando via mail il file html completo che ho usato.

 Ti mando via mail il file html completo che ho usato.
Non metterti a ridere, ma questi sono i tempi riscontrati col mio PC.
Nell'ordine in cui li hai postati:
IE - 31.284/242.282/l'ho interrotto dopo un blackscreen :-/
OP - 66.562/261.596/247.202
FF - 26.288/115.476/36.316
CPU sempre al 100%
Grazie di tutto.
-- 
    * b *
  *   y   *
*   Piero   *
#v+
-errare humanum est-
#v-

 Grazie di tutto.
Di niente.
Piu' che altro spero di averti provato che le espressioni regolari sono 
il modo piu' indicato per risolvere questi problemi e di averti dato uno 
spunto per fare test usando delle semplici sottrazioni di date.

 date.
Si, con la "pappa scodellata", ho potuto constatarlo, e l'uso delle date
(cronometro sigh!) per calcolare il tempo � interessante e abbastanza
semplice anche per me, il ch� � tutto dire. ;-)
Bye.
-- 
    * b *
  *   y   *
*   Piero   *
#v+
-carpe diem-
#v-