Newsgroup: it.comp.www.php
Titolo: preg_match che matcha troppo

Ciao a tutti,
Ho questi due file, uno us-ascii pulito, l'altro contente dei byte sposchi:
$ file -i rich_unic_ascii.txt
rich_unic_ascii.txt: text/plain; charset=us-ascii
$ file -i rich_unic_non_ascii.txt
rich_unic_non_ascii.txt: application/octet-stream; charset=binary
Perché il seguente preg_match mi matcha tutte le righe del file us-ascii?
$i=0;
$h = fopen('rich_unic_ascii.txt','r');
while ($l = fgets($h)) {
	if (preg_match('/[^(\x01-\x7F)]*/', $l)>0) {
		$i++;
		echo "$i] NON ASCII\n";
	}
}
-- 
g4b0, linux user n. 369000
http://brosulo.net

 	if (preg_match('/[^(\x01-\x7F)]*/', $l)>0) {
Secondo me per l'asterisco.

 if (preg_match('/[^(\x01-\x7F)]*/', $l)>0) {
 /[^(\x01-\x7F)]+/


Perfetto!! In effetti * == 0 o piú, é un po' ampia come ricerca...
Il problema, peró, non é risolto del tutto... Ora vorrei sostituire 
TUTTE le occorrenze di caratteri non ASCII con uno spazio, anche nel 
caso in cui queste siamo adiacenti.
Usando preg_replace con la regexp di cui sopra mi sostituirebbe due 
caratteri non ASCII adiacenti con uno spazio solo, o sbaglio?


 caratteri non ASCII adiacenti con uno spazio solo, o sbaglio?
togli il +  e dovrebbe andare


Perfetto, ora funziona. Ed ho anche capito bene come funziona 
preg_replace :)



Mi rimangio ció che ho detto! Anzi, la preg_replace fa quel che deve, ma 
il problema é piú complesso: I file che processo *dovrebbero* essere 
ASCII puro, ma putroppo non é sempre cosí. Alle volte mi trovo dei 
caratteri sporchi, cioé non facenti parte del set ASCII.
Il problema é che alle volte questi caratteri sono di *2 byte* perché 
l'encoding prevede cosí (es. Á in non so quale encoding diventa, in 
esadecimale, 0xC2 0x85), ma io li devo comunque convertire in uno 
spazio, essendo il file che processo un txt a campi fissi (no comment, 
ho a che fare con applicazioni scritte prima dell'avvento di XML :P)
Come la risolvo?!?


 Come la risolvo?!?
Con un semplice programma in C converti tagli tutti i caratteri 
superiori a 127 convertendoli in spazii, dallo script PHP esegui il 
programma sul tuo file. Eventualmente puoi avere due cartelle in modo da 
non dover sanitizzare file già esaminati.


Non risolvo comunque, perché come faccio dal programma C a capire se un 
byte>127 é a se stante, o fa parte di un gruppo di 2, 3 o 4 byte di 
qualche encoding particolare?
Alla fine la lunghezza della riga deve essere sempre di 200 byte, ma non 
posso togliere spazi random in caso di lunghezza > 200byte, in quanto si 
tratta di un txt a campi fissi, di quelli che escono dai mainframe anni 
'70 per intenderci...
Esempio per farvi capire il tipo di file: il cognome inizia al char 25 
ed é lungo 30 char, al byte 55 inizia il nome lungo 30 e cosí via.


 qualche encoding particolare?
Non puoi risolverlo con una "semplice" regexp. E` un problema di 
encoding, 
quindi ti devi passare il file byte per byte, con sottomano le specifiche 
di quel formato, e convertirlo.
Se non hai le specifiche del formato non puoi farci niente.
Bye.

 Se non hai le specifiche del formato non puoi farci niente.
da quello che scive nell'ultimo messaggio sembra che le specifiche di 
formato le abbia.
E mi sembra che php sia la strada sbagliata, io proverei a vedere cosa ha 
python


Il problema é che il file *DEVE* essere formattato in ASCII, ma chi lo 
invia lo manda sporco. Sporco di cosa non é dato saperlo, e non é 
neanche un qualcosa di ricorrente, per cui non saprei neanche a quali 
specifiche aggrapparmi. Sembra che qualcuno prenda il file generato dal 
mainframe e lo modifichi a mano con qualche editor windowsiano, che usa 
chissá quale encoding!
La soluzione piú ovvia sarebbe rispedirlo al mittente con un 
bell'errore, ma purtroppo noi siamo $piccolaSoftwareHouse e loro sono 
$piuGrandeBancaItaliana per cui abbiamo torto solo e sempre noi. Punto.
Attualmente ho un alert che mi avvisa quando si verifica questa 
situazione, ed intervengo a mano. Vorrei poter automatizzare la cosa, ma 
la vedo buia...
Conosco il C, il python lo posso studiare, ma qui il problema sta al di 
sopra del linguaggio di programmazione, quello che devo trovare é un 
metodo per scartare tutto ció che non é ASCII sostituendolo con un 
singolo carattere di spazio, a prescidere da quanti byte é composto!


 singolo carattere di spazio, a prescidere da quanti byte é composto!
Capisco la pressione del GrossoCliente(tm) ma non ci vedo niente di male 
a dirgli "i file che ci mandate sono codificati in modo non standard. 
Dateci il formato in cui li codificate altrimenti non possiamo fare il 
lavoro".
Senza il formato come fai a sapere da quanti byte e` composto un 
"carattere"? Se il primo byte con 101xxxxx significa "prendi un byte 
dopo" e 110xxxxx significa "prendine due", e 111xxxxx significa "prendine 
tre" lo devi trattare in un modo. Se la codifica e` 100, 110, 1110 invece 
di 101, 110, 111 lo devi trattare in un altro.
Ripeto: se non sai la codifica non vai da nessuna parte. I byte non hanno 
"meta-tag" nascosti nei picchi ascendenti di tensione dei flip flop che 
ti dicono quanti byte devi prendere dopo.
Bye.

qualche encoding particolare?
Se il byte, in AND con 0xE0, ti da' 0xC0, allora puoi supporre che sia una
sequenza UTF8 di 2 byte. Se il byte successivo, in AND con 0xC0, da' 0x80,
la supposizione e' confermata; puoi convertire i due byte in ASCII, usando
utf8_decode o una tabella, oppure in uno spazio (shiftando di 1).
Se in AND con 0xF0 hai 0xE0, potrebbe essere una sequenza di 3. Se i bytes
successivi danno ambedue 0x80 in AND con 0xC0, e' cosi'. E altrimenti, hai
uno (o due, o tre) caratteri Win1252 che puoi convertire o eliminare.
Se in AND con 0xF8 hai 0xF0, sequenza di quattro. Come sopra.
In tutti gli altri casi potrebbe essere un encoding ISO-8859* o CP850, che
pero' puoi trattare facilmente sostituendo il byte con 0x20 e proseguendo.
Avevo il codice da qualche parte, ma, a ritrovarlo... (forse l'ho postato,
tu googla, non si sa mai).
Leonardo che li conosceva bene, quelli di ${BANCA}
-- 
Enough, enough!  But, stranger, ere we part,
Glancing farewell to each nefarious bier,
This warning would I beg you take to heart:
There is an end to e'en the worst career!

 da quanti byte é composto!
Cioè lo devi convertire, o lo smazzi a mano oppure ti appoggi a libiconv.

 Leonardo che li conosceva bene, quelli di ${BANCA}
Tempo fa avevo scrito questa funzione, non so se contiene tutti i
caratteri di cui c'è bisogno, ma si può espandere e forse può essere
utlie:
function correggi($testo) {
        $testo = rawurlencode($testo);
        $hex = array(
                "%93",
                "%94",
                "%92",
                "%AB",
                "%BB",
                "%E0",
                "%F9",
                "%E9",
                "%E8",
                "%EC",
                "%F2",
                "%5F",
                "%2D",
                "%96",
                "%97",
                "%85",
                "%C8",
                "%95",
                "%B0",
                "%27",
                "%B4",
                "%AA",
                "%AE",
                "%CC",
                "%91",
                "%FC",
                "%BA",
                "%80",
                "%E1",
                "%C9",
                "%EA",
                "%E2",
                "%A0",
                "%F6",
                "%DF",
                "%B2",
                "%A9",
                "%E7",
                "%A3",
                "%DC",
                "%D6",
                "%D1",
                "%C0",
                "%C0",
                "%C8",
                "%C9",
                "%D9",
                "%DA",
                "%D2",
                "%C5",
                "%D8",
                "%D3",
                "%C4",
                "%C1",
                "%CD",
                "%8E"
        );
        $html = array(
                "&ldquo;",
                "&rdquo;",
                "&rsquo;",
                "&laquo;",
                "&raquo;",
                "&agrave;",
                "&ugrave;",
                "&egrave;",
                "&egrave;",
                "&igrave;",
                "&ograve;",
                "&#8211;",
                "&#8211;",
                "&#8211;",
                "&#8211;",
                "&hellip;",
                "&Egrave;",
                "&bull;",
                "&deg;",
                "&rsquo;",
                "&acute;",
                "&ordf;",
                "&reg;",
                "&igrave;",
                "`",
                "&uuml;",
                "&deg;",
                "&euro;",
                "&aacute;",
                "&Egrave;",
                "&ecirc;",
                "&acirc;",
                " ",
                "&ouml;",
                "&yuml;",
                "&sup2;",
                "&copy;",
                "&ccedil;",
                "&pound;",
                "&Uuml;",
                "&Ouml;",
                "&Ntilde;",
                "&Agrave;",
                "&Aacute;",
                "&Egrave;",
                "&Eacute;",
                "&Uacute;",
                "&Ugrave;",
                "&Ograve;",
                "&Aring;",
                "&Oslash;",
                "&Oacute;",
                "&Auml;",
                "&Aacute;",
                "&Iacute;",
                "&#381;"
        );
        $newTesto = str_replace($hex, $html, $testo);
        $newTesto = rawurldecode($newTesto);
        //$theText = trim($newTesto);
        //$newTesto = mb_convert_encoding($newTesto,"UTF-8");
        return $newTesto;
}
-- 
http://www.maxori.it
L'Arte è la capacità di fare cose di nessun valore
e di riuscire a venderle
F. Zappa

 tu googla, non si sa mai).
Qualche hint su cosa cercare? :)
Comunque la tua soluzione sembra quella giusta, sei sicuro di aver preso 
in considerazione tutte le casistiche?
Grazie ancora


in considerazione tutte le casistiche?
La domanda inizia con "sei sicuro", pertanto la risposta e' "no" :-D
Comunque, per come funziona UTF8, puoi anche fare cosi':
	int	s;
	char	*p, *q;
	for (s = 0, p = q = string; *p; p++)
	{
		if (*p & 0x80)
		{
			if (!s++)
				*(q++) = 0x20;
			continue;
		}
		else
			s = 0;
		if (p!=q)
			*(q++) = *p;
		else
			++q;
	}
	*q = 0x0;
Leonardo senza garanzie
