Perl regexp (szám vagy szöveg)

Perl regexp (szám vagy szöveg)

Hozzászólások

Szöveges, adatokat tartalmazó állományból válogatom szét a mezőket, ami lehet szám vagy szöveg típus, így:
[code:1:880e19ad49]
/(^\-|^\d+)(\,?\d*)*\.?\d*$/
[/code:1:880e19ad49]
A számoknak ilyen formái fordulhatnak elő:
0
0.00
.1
0.123
123,456,789.00
plusz az eddigiek negatív előjellel (kivéve a nullát)

A szövegnek ilyen formái lehetnek:
szöveg
123abcd123
0123456

Abban kérném a segítséget hogy a fenti regexp -et kellene kiegészíteni azzal hogy a "0123456" adat az szöveg típus legyen, viszont a "0" és a "0.0" az szám legyen. Egyszerűbben fogalmazva: az a mező ami nullával kezdődik és hosszabb mint 1 és nem tizedesponttal folytatódik az legyen szöveg típus.

ELaci

Például:

[code:1:31c21a274f]
#!/usr/bin/perl -wn

chomp;
if ( /^-?([1-9][,\d]+|0)(\.\d+)?$/ ) {
print "szam: $_\n";
}
else {
print "nem szam!\n";
}
[/code:1:31c21a274f]

Ja, bocsi, ez elfogadja a -0 -át. Akkor bonyolultabb:

[code:1:15af79304b]
/^(-?[1-9][,\d]+(\.\d+)?|0(\.0+)?|-?0\.\d+[1-9]\d+)$/
[/code:1:15af79304b]

[quote:5238b52501="cln"]ami lehet szám vagy szöveg típus, így:
[code:1:5238b52501]
/(^\-|^\d+)(\,?\d*)*\.?\d*$/
[/code:1:5238b52501]
Abban kérném a segítséget hogy a fenti regexp -et kellene kiegészíteni azzal hogy a "0123456" adat az szöveg típus legyen, viszont a "0" és a "0.0" az szám legyen. Egyszerűbben fogalmazva: az a mező ami nullával kezdődik és hosszabb mint 1 és nem tizedesponttal folytatódik az legyen szöveg típus.
ELaci

tipus? a perl nem egy tipusos nyelv! az adatok hasznalatabol derul ki, hogyan is kene ertelmezni.
perl -e '$_ = "foo";print 5+$_' -> 5
perl -e '$_ = "0.2";print 5+$_' -> 5.2

egyedul a 343,534,345 adataiddal lehet baj, ezt numerikus kornyezetben sem fogja szamkent kezelni.

[quote:b1a558da41="klao"]Ja, bocsi, ez elfogadja a -0 -át. Akkor bonyolultabb:

[code:1:b1a558da41]
/^(-?[1-9][,\d]+(\.\d+)?|0(\.0+)?|-?0\.\d+[1-9]\d+)$/
[/code:1:b1a558da41]

Ez jónak tűnik, mindjárt próbálkozok vele. :D

Elaci

[quote:33bae36063="xbit"][quote:33bae36063="cln"]ami lehet szám vagy szöveg típus, így:
[code:1:33bae36063]
/(^\-|^\d+)(\,?\d*)*\.?\d*$/
[/code:1:33bae36063]
Abban kérném a segítséget hogy a fenti regexp -et kellene kiegészíteni azzal hogy a "0123456" adat az szöveg típus legyen, viszont a "0" és a "0.0" az szám legyen. Egyszerűbben fogalmazva: az a mező ami nullával kezdődik és hosszabb mint 1 és nem tizedesponttal folytatódik az legyen szöveg típus.
ELaci

tipus? a perl nem egy tipusos nyelv! az adatok hasznalatabol derul ki, hogyan is kene ertelmezni.
perl -e '$_ = "foo";print 5+$_' -> 5
perl -e '$_ = "0.2";print 5+$_' -> 5.2

egyedul a 343,534,345 adataiddal lehet baj, ezt numerikus kornyezetben sem fogja szamkent kezelni.

A folyamat nem perl-ben folytatódik, hanem OOo vagy excel táblázat lesz belőle és oda kell megadni a típust. A vezető nullával rendelkező numerikus adatnál viszont levette a nullát, és ha ez egy azonosító kód volt, akkor elromlott.

Elaci

[quote:412ce10dc8="klao"]Ja, bocsi, ez elfogadja a -0 -át. Akkor bonyolultabb:

[code:1:412ce10dc8]
/^(-?[1-9][,\d]+(\.\d+)?|0(\.0+)?|-?0\.\d+[1-9]\d+)$/
[/code:1:412ce10dc8]

Kipróbáltam, és nem jó, mert a vezető nullával rendelkező adatot is számként értelmezi és emiatt lemarad a nulla az elejéről. :(
Még variálok rajta én is, hátha...

ELaci

Végül is egyszerűsítéssel megoldottam a dolgot:
[code:1:ddc9efa61d] /^0\d+$/[/code:1:ddc9efa61d]
ezzel a regexp-el csak a nullával kezdődő adatokat figyelem, és ha ráillik akkor az is szöveg lesz.

ELaci

[quote:d3d557b96c="cln"][quote:d3d557b96c="klao"]
[code:1:d3d557b96c]
/^(-?[1-9][,\d]+(\.\d+)?|0(\.0+)?|-?0\.\d+[1-9]\d+)$/
[/code:1:d3d557b96c]

Kipróbáltam, és nem jó, mert a vezető nullával rendelkező adatot is számként értelmezi és emiatt lemarad a nulla az elejéről. :(
Még variálok rajta én is, hátha...

ELaci

Hmm. Ez fura. Nekem jól működik. :(
Persze, ha az egyszerübb megoldás is elfogadható számodra, akkor azt érdemes használni, mert arról legalább látni lehet, hogy mit csinál. :)

ha mezoker parsols, akkor a te baratod inkabb a pack/unpack paros :) nemileg hatekonyabb, de (elsosorban) fix hosszu mezokre valo.

[quote:134e429936="anr"]ha mezoker parsols, akkor a te baratod inkabb a pack/unpack paros :) nemileg hatekonyabb, de (elsosorban) fix hosszu mezokre valo.

A gond az hogy a bemenő adatra semilyen meghatározott formátum nem írható elő, elképesztően sokféle lehet. Van pl. rekordonként 5-160 váltózó mennyiségű mezőből álló file is. Annyi a lényeg hogy ami láthatóan numerikus az inkább legyen numerikus, és ami szöveg az meg legyen szöveg. Valójában mindegyik lehetne szöveg típus, de így a felhasználóknak egy fokkal kényelmesebb.

ELaci

Hmm. Ez fura. Nekem jól működik. :(
Persze, ha az egyszerübb megoldás is elfogadható számodra, akkor azt érdemes használni, mert arról legalább látni lehet, hogy mit csinál. :)

Nem tudom az okát, de pl. a "08011" adatból "8011" szám lett. Végül is a dolog az én megoldásommal, kis szépséghibával de működik, és köszönöm a segítséget.

ELaci

[code:1:9b9c94da15]
grep '^\(-\?\(\([0-9]\{3\},\)*[0-9]\{1,3\}\)\?\.[0-9]\+\|0\)$'

Mivel kicsit write-only és lehet, hogy nem tökéletes, részletezném:
(A ki-escape-elendő karaktereket a láthatóságért direktben írom)
- Hármas számcsoportok, vesszővel lezárva: '[0-9]{3},'
- Ebből opcionálisan sok, esetleg egy sem: '([0-9]{3},)*'
- Ez után 1..3 db számjegy: '([0-9]{3},)*[0-9]{1,3}'
- Ez opcionálisan (azaz az egészrész): '(([0-9]{3},)*[0-9]{1,3})?'
- Egy pont, mögötte legalább egy db számjegy: '\.[0-9]+'
- Az egészrész plusz a fenti törtrész: '(([0-9]{3},)*[0-9]{1,3})?\.[0-9]+'
- Mindez előtt egy db opcionális minusz: '-?(([0-9]{3},)*[0-9]{1,3})?\.[0-9]+'
Na ez a szimpla szám, amit keresel.
- Egy db nulla önmagában: '0'
Ez a külön kezelendő nulla.
A kettő VAGY-kapcsolata: '(-?(([0-9]{3},)*[0-9]{1,3})?\.[0-9]+)|0'
Ez előtt és mögött a sorkezdet és -végjel:
'^(-?(([0-9]{3},)*[0-9]{1,3})?\.[0-9]+|0)$'
Ebben ki-escape-elve a "(){}|?+" karaktereket:
'^\(-\?\(\([0-9]\{3\},\)*[0-9]\{1,3\}\)\?\.[0-9]\+\|0\)$'
Na ez van fent a grep mögött :).
[/code:1:9b9c94da15]
Ezzel teszteltem, elvileg a felső blokk a jó:
[code:1:9b9c94da15]
0
0.00
.1
0.123
123,456,789.00
-.1
-0.123
-123,456,789.00
001,123.00

-0
1.
.
123,456,789
001123.00
12
123abcd123
0123456
-123abcd123
-0123456
[/code:1:9b9c94da15]

Őszintén szólva, az az érzésem hogy itt kezdődik a fekete mágia. Valszeg sokan ezért nem szeretik a perl-t, mert túlságosan igénybeveszi az agytekervényeket. Annak idején, amikor én még nagyüzemileg sakkoztam, akkor a túl bonyolult helyzeteket egyszerűsítettem, hogy saját magam részére is átláthatóvá tegyem hosszú távon is. Megpróbálom azonban értelmezni az általad javasolt megoldást és köszönöm a fáradozást.

ELaci