regex optimalizás, tagadás

 ( GCS | 2015. február 16., hétfő - 11:25 )

Készítettem egy RegEx-et, működik is: ^\+36((1|20|30|31|70)\d{7}|(?!(1|20|30|31|70))\d{2}\d{6})$
Kérdés, lehet-e optimalizálni vagy a (?!...) részt átírva jobb-e a ^\+36((1|20|30|31|70)\d{7}|[^(1|20|30|31|70)]{2}\d{6})$ kifejezés?

Hozzászólás megjelenítési lehetőségek

A választott hozzászólás megjelenítési mód a „Beállítás” gombbal rögzíthető.

20|30|70 => [237]0

\d{2}\d{6} => \d{8}

t

+1
\d{2}\d{6} az olvashatóságért maradt bent, egyébként jogos.
[237]0 nem lassít az eredeti helyett?
Egyik fórumban arról olvastam, nagyban nyelvfüggő, melyikben hogyan programozták le a RegEx engine-t. :-/

Érzésre szerintem gyorsabb, mert a | nál többet kell vizsgálnia, mint 1 karakter.

Szerintem rendes regex lib esetén pont ugyanaz lesz a végeredmény. Ugyanis egy végesautomatává kell fordulnia a kifejezésnek, az pedig meg fog egyezni.

Az 1-esre pedig nincs szükség külön, hisz 1 + 7 jegy ugyanannyi, mint 2 + 6

Valamelyikünk félreérti. 1-est Budapest miatt kell megkülönböztetni. Akkor 7 további számjegyre van szükség. Második regex második részére utalsz? Az olyan két számjegyet ír elő, ami nem 1-essel kezdődik és hat másik követi. Bár ahogy nézem ez kizárja a 10-19 körzeteket. :( Mindjárt megnézem tesztelőben.

De mi a különbség a
+36 1 1234567 és
+36 11 234567 között? semmi. Felesleges megkülönböztetni. A BP-i számokat lehet úgy is venni, hogy 10-19-es köretszámok + 6 jegy mint ahogy máshol.

Ill akkor lehet csak gond, ha a BP-i 1-es után nem lehet 0, de ezt a te regexed sem kezelte, én csak azzal kompatibiliset mondtam.

Érvelésed jogos, de ha átírtam ^\+36((31|[237]0)\d{7}|[^(31|[237]0)]{2}\d{6})$ -re, akkor se a bp-i, se a 1x körzetek nem mennek.

Nekem igazából már az eredeti sem megy.
Eredeti: ^\+36((1|20|30|31|70)\d{7}|[^(1|20|30|31|70)]{2}\d{6})$
Picit javítva: ^\+36((1|20|30|31|70)\d{7}|[^(1|20|30|31|70)]\d{2}\d{6})$
Szóval sztem ezek nem jók.

Bocs, vmit elnéztem, ezt még vizsgálom
Na megvan, itt a nem pesti és nem mobilok nem mennek nekem

A te regexedre
^\+36((31|[237]0)\d{7}|[^(31|[237]0)]{2}\d{6})$
Pedig expected end of string at position 45-öt kapok

Tehát rövidségben eddig a ^\+36((31|[237]0)\d{7}|(?!(31|[237]0))\d{2}\d{6})$ a nyerő. Persze performanciában lehet jobb kifejtve a 20-30-70
Ha más formában is le tudod írni és szeretnéd írhatok rá egy kis proggit, ami "megméri" melyik a gyorsabb pár 10-100 ezer random generált telefonszámra.

Mármint [^...] formába? Mert a (?!...) lehetőséget nem tudom, támogatják-e széleskörűen.

Nekem a (?!...) működött és a [^...] nem
The Regex Coach-csal néztem

+1 [^...] mégsem működik rendesen, helyes számokra sincs egyezés.

Kevered a (negált) karakterlistát a vagylagos részkifejezéssel.

Ennek ugyan van jelentése, de nem valószínű, hogy az, amit tulajdonítani szeretnél neki:

[^(31|[237]0)]

Egyébként tanácsos kanonizálni, hogy mivel akarjátok meghajtani azt a reguláris kifejezést, mert anélkül végtelen "nekem megy - érdekes, nekem meg nem" dialógus lesz a topic.

Utóbbi regex motor függő lehet. Egyikkel nekem zárójelezési hibát ad. Másikkal szépen működik.

Tényleg semmi, mert egyik sem valid hívószám: Bp.-en nincs 1-gyel kezdődő hívószám, illetve kétjegyű körzetszám nem kezdődhet 1-gyel. Ha mindenképp le akarod választani a körzetszámot, akkor 1-gyel kezdődő esetben 1+7, nem 1-gyel kezdődő esetben meg 2+6 jegyre kell bontani a számot.

Oké, de nyilván érted mit mondtam... Az első hozzászólásban lévő regex is elfogadja a BPi 1-gyel kezdődő számokat, de jó, akkor legyen
+36 1 2345678 és
+36 12 345678
Ezért felesleges (ha nem akarunk teljesen pontos ellenőrzést csinálni) külön vizsgálni a BPi és nem BPi számokat.

Én csak a kérdésre válaszoltam, nem néztem, hogy mi az a szám amit még el kéne fogadnia. Pl a 38 és 50-es körzetek is 7 jegyűek, a 71-es pedig 10. És egy csomó körzetszám nem is létezik. Én bevallom ezeket nem tudtam, nem is figyeltem rá, de akinek fontos, az úgyis rákeres az interneten.

Ha lehet kék is, zöld is, meg macska is, akkor mit ellenőrzöl illetve minek? :)

Erre azt hiszem a kérdező már megadta a választ: "Másrészt nem nekem kell eldönteni hogy valós-e a szám (létezik-e ténylegesen adott körzetszám), mert azt előzőleg ellenőrizték már. Nekem csak annyi kell, megfelel-e egy általános mintának a szám (nem írták-e el felvitelkor). Mobilnál és bp-i számnál legyen 7 további számjegy az előfizető azonosítására, míg egyéb körzetszámoknál hat darab számjegy."
Szóval ha ő azt mondja, hogy elég, ha a számjegyek száma stimmel BPi számok esetén, akkor mért kérdőjelezed meg a szándékát?
Az általam írt példa tényleg rossz volt, de a hangsúly nem az 1-es körzetszám utáni 1-esen volt, lehetett volna ott bármi más, úgyhogy nem érzem jogosnak, hogy abba kötöttél bele.

Most mégis közétek "lövök". Elírás lehet nem létező körzetszám felvitele is. Egy pontosabb, de lassabb megoldás: ^\+36((1|20|21|30|31|50|70)[1-9]\d{6}|((2[23456789])|(3[234567])|(4[02456789])|(5[234679])|(6[23689])|(7[23456789])|(8[02345789])|(9[01234569]))[1-9]\d{5})$
Ezt majd egyszerűsítem, ha megéri.

Mi lesz a +3680000000 számmal?

Van listád arról, Bp számok milyen mintát követnek? Abból indultam ki, telefonszámok nem kezdődnek nullával. De 1-el sem, legalábbis Bp-en?

Per pillanat nincs a birtokomban aktuális számozási terv, de emlékeim szerint a hét, illetve vidéken hatjegyűre váltás után nem kezdődhettek a hívószámok egyes számmal. Valid telefonszámok (nagyjából átgondolva a számozást):
-ha 9 jegyű, akkor 20, 30, vagy 70 az első két jegy, és a 3. jegy pedig nagyobb, mint egy.
-nyolc jegyű, és az első jegy 1, akkor a második nagyobb, mint egy.
-nyolc jegyű, az első nagyobb, mint egy, a második nem nulla, a harmadik nagyobb, mint egy.
-nyolc jegyű, és a második jegy 0, és az elsőn 4, 5, 8, vagy 9. (A 20, 30, 70 hibás mobil, 60 megszűnt NMT (W450))
A nyolcnál kevesebb számjegy ha jól tudom, 3, 4, vagy 5 jegy esetén lehet valid.
De tényleg egyszerűbb, ha a valid körzetszámok benne vannak egy táblázatban, aztán az és az adott körzetszámhoz tartozó valid hívószámok hossza és a "hívószám első jegye nem lehet 1" alapján vizsgálod a számokat.

Ez a szabály a földrajzi és mobil számokra igaz.
A listákat innen tudod letölteni: http://webpub-ext.nmhh.hu/aga/common/setLanguageAction.do?lang=hu
Azért dumálok annyit, mert tényleg listák, amiket lehet visszafelé algoritmizálni. Aztán van olyan is, amiket még nekem sem sikerült.
Szerintem azon küzdesz, hogy olyan számokat validáljál, amely végén ember van. Ezek a számok is leírhatók listában:
11999999 - invalid
19999999 - valid
22199999 - invalid
22999999 - valid
...
Ebben egy seek >= megmondja, hogy valid vagy invalid.
De ha berakod a
51999999 - Internet hozzáférési szolgáltatás
80999999 - zöld szám
rekordot, akkor azt is tudod. Stb...

Akkor inkább innen, egyben: http://webpub-ext.nmhh.hu/aga_xml

^\+36(?:70|[23][01]|\d)\d{7}$

Ennél rövidebben nem tudom.
A dolog trükkje, hogy az alternation definíció szerint az első találatig megy, nincs backtrack. Így a zárójeles kifejezés a 20, 21, 30, 31, 70 körzetek esetén a körzetszámot, egyébként a körzetszám első számjegyét adja vissza (ami Budapest esetében maga a körzetszám).
A dologgal egyébként elvi problémám van: mi értelme ilyen szinten ellenőrizni? Ha már ezt csinálod, arra is tesztelni kéne, hogy az adott körzetszám létezik-e, illetve értelmes-s. (Ha pl. ügyfél telefonszámát kéred be, az 51 biztos nem lesz jó, pedig valós körzetszám.)

Ez nálam elfogadja a +3620123456-ot és a +36211234567-et is, noha egyiket sem kéne.

Bevallom, én nem teszteltem :) Mivel nézted? (A második számot el kell fogadnia, a 21-es számok hétjegyűek.)

Ok, ezt nem tudtam, az eredeti leírásban csak 20,30,31 és 70 volt:)
The Regex Coach-csal néztem, de nem hiszem, hogy ez lenne a gond. Most megnéztem ezen az online regex tester oldalon is: http://regexpal.com/
Szintén elfogadja.

Basszus, kimaradt a nagyobbjel, így illeszkedés hiányában mégis lesz backtrack...
^\+36(?>[23][01]|70|\d)\d{7}$

Ha elmondanád saját szavaiddal, hogy mit szeretnél elérni, akkor megmondom hogyan kell csinálni. :)

Ha nem látszik az eredeti kiírásból, akkor nem tudod megcsinálni. :)

Aggódásod megható, de én már rég megcsináltam. Csak úgy, hogy még működik is. ;)
Arra utalék. Vala.
Ezek a regexpek nem írnak le Magyarországon használatos hívószámokat, tehát rosszak.
Felesleges gyorsítani őket, mivel ez a módszer igen lassú.
Ha ez valamilyen iskolai feladat, akkor biztosan regexp használata a cél.
Ha meg dolgozni szeretnél vele, azt másképp kell tenni!
Gondoltam segítek...

Mosoly jellel írtad és én is a választ. Gyorsítani nem nagyon akartam és nem iskolai feladat. De legalább elismerted hogy nagyon is tudod, miről szól a topic.
Tehát mindenképpen függvényt írnál és saját magad dolgoznád fel a szöveget?

Halk megjegyzés: Elég sok, mondhatni napi kapcsolatban volt a kolléga a telefonszámok világával, meg a feldolgozásukkal, úgyhogy nagyobb sejtése lehet arról, miről szól a topic, mint te gondolod.

Nem a tudását akartam megkérdőjelezni, max a stílust, miközben a végén elismerte, hogy tudja miről van szó. Mindezt mosoly jellel ahogyan ő is tette. Röviden, sértődést sem szerettem volna.

Oké, nekem könnyebb, szűk három év alatt volt időm megszokni :)

Akkor majd egyszer bemutatsz neki. Bár feltételezem, hogy nem emlékszel rám. Már vagy öt éve találkoztunk utoljára, ha nem több. :-|

Bucko kollégát szerintem még régebben láttam :-P

Azt azért tudod, ki vagyok? :)

Fotó alapján rémlik valami... ;)

Törölhető.

Legyen függvény, de inkább C szűrő. Bár awk-ban is készítettem egy kisöccsét.
Ez a kifejezés +361\d{7} helyesen leírva... A továbbiakban nem írom a +36-ot, és a számokat tartalmazó mezőt"=T van a kezünkben. ...Így is meghatározható:
12000000 <= atoi(T) <= 19999999
A vizsgált körzetszámokra készíthető egy lista. (Alias adatbázis.)
No, ez már megfelel a Nemzeti Számozási Tervnek, de nem biztos, hogy érvényes a hívószám.
Ehhez a "kijelölt" állapotú számmezők listájáig kell finomítani az adatbázisunkat.
A teljesség kedvéért ehhez még hozzá kell tenni a hordozott számok listáját, és akkor kiderül minden megfelelő formátumú, egyúttal létező hívószám.

A fenti ábrázolás lényege az a felismerés, hogy 32 bites int-be belefér bármelyik telefonszám, ezért gazdaságosan tárolható. Az előforduló kb. 15M telefonszám mindössze 60MB-ba sűríthető.

Az előnye :), hogy ilyet nem lehet sql-ben tárolni, de pl. BerkelyDb vagy asszociatív tömb (awk) kiválóan megfelel.

Természetesen nem szükséges ilyen szószátyár módon diszket pazarolni! Elegendő a létező számmezőkre egy index (4 byte), amelyhez tartozik 1000x1 bit, azaz 129 byte/számmező. Ez a tárolási mód < 10MB adatmennyiséget jelent, így gyorsan lekérdezhető.

Itt sajnos kötve vagyok PHP5.x-hez, webes oldalnál egy hosting cégnél, ahol nincs CLI hozzáférésem. Egyéb okokból a MySQL-hez is kötve vagyok és hogy abban kell tárolnom az egyes telefonszámokat pár járulékos adattal, amik előfordultak.

Ez van - anno takarékosan kellett bánni az erőforrásokkal, most meg ez sajnos egyre kevésbé szempont :)

Feladat függő. Kellett nekem többgépes prímszámkeresőt írnom, sok GB RAM társaságában gépenként (párhuzamos programozás). Fordított nyelvről lévén szó, ott tudtam élni a bitekre való leképzéssel meg persze pár egyéb trükkel. Egész jó lett és (számomra) meglepően gyors.

Telefonszámok terén meg kb összesen háromezerről van (eddig) szó, kb 50 db-al ha bővül és kb 70-80 lekérés lehet hétköznaponként. Másrészt nem nekem kell eldönteni hogy valós-e a szám (létezik-e ténylegesen adott körzetszám), mert azt előzőleg ellenőrizték már. Nekem csak annyi kell, megfelel-e egy általános mintának a szám (nem írták-e el felvitelkor). Mobilnál és bp-i számnál legyen 7 további számjegy az előfizető azonosítására, míg egyéb körzetszámoknál hat darab számjegy. Szó sincs tárolási optimalizációról vagy egyebekről. Ezért döntöttem szimpla regex ellenőrzés mellett.

Azért be lehet rakni MySQL-be is a limiteket. Seek >= és a találat mellé kell egy flag, ami jelzi a számmező érvényességét. Azért érdemes megcsinálni, mert az adat az adat marad, és nem kerül a kódba.

Gondolj bele, ha megváltozik a számozási rendszer! Betöltöd az új limiteket, aztán már csak a felmarkolt zsozsót kell elszállítani a kocsmába. :)