Regulární výraz - ne a ne opravit (C#)

PiF

Regulární výraz - ne a ne opravit (C#)
« kdy: 25. 09. 2011, 14:27:56 »
Ahoj,

snažím se, ale ne a ne opravit jednoduchý regulární výraz.
Soubor obsahuje 2 klíče v uvozovkách oddělené čárkou: "něco","něco"
Výraz: "\",\"" parsuje výborně.
Je to v C# a pomocí
string[] rdata = Regex.Split(lRadek.Trim(), "\",\"");
z toho udělám 2 zánamy, ty co potřebuji.
Funguje to výborně u 15998 z 16000 záznamů.
Ty dva vypadají nějak takhle: "něco"",""","něco"
Takový řádek je rozparsován dle očekávání blbě.

Zkouším všechno možné i nemožné. \"[^\"],\"[^\"] nebo třeba "\"(?!\"),\"(?!\")"  + hromadu různých dalších kombinací, abych vyloučil v textu se objevující "",""

Zkouším to rozepisovat možně i nemožně...
string[] rdata = Regex.Split(lRadek.Trim(), "[^\"]\"{1},\"{1}[^\"]");

Ale text "blabla "",""","blabla" z toho prostě nejsem schopný získat jako klíč blabla "","" a druhý blabla, ale vždycky z toho mám "blabla " a nějaký nesmysl.

Pokud někoho z Vás napadne co s tím, budu rád.
Díky!
PiF


MilanK

Re: Regulární výraz - ne a ne opravit (C#)
« Odpověď #1 kdy: 25. 09. 2011, 15:13:05 »
Do toho bych se vůbec nepouštěl pomocí regulárních výrazů.

Potřebuješ to rozdělit v místě, kde je čárka (to lze jednoduchým RE). Před touto čárkou musí být sudý počet uvozovek (to už je rozšířený RE -- takové to "(?<=...)"). To by se ještě dalo, pokud C# umí takovou rozšířenou syntaxi RE. Ale těžko tomu někdo porozumí, až bude Tvůj kód číst - něco jako:

     (?<=^([^"]*"[^"]*")*[^"]*),

Ale nedají se uvozovky ještě nějak "escapovat"? Není povoleno něco jako

"toto je uvozovka: \"; je nutné ji ukládat jako \\\"; protože by jinak kolidovala s koncem pole"

Jakmile v tom budou ještě ta zpětná lomítka, tak už bych RE vůbec nezkoušel.

tom__beta

Re: Regulární výraz - ne a ne opravit (C#)
« Odpověď #2 kdy: 25. 09. 2011, 16:50:57 »
Co nieco taketo ??

Kód: [Vybrat]

string input = "\"key\"\",\"\"\",\"value\"";
//string input = "\"key\"\",\",\"value\"";
//string input = "\"key\",\"value\"";

Regex exp = new Regex("^\"((?:[^\"]|\"\")*)\",\"((?:[^\"]|\"\")*)\"$");

Console.Out.WriteLine(exp.Replace(input, "$0 --> Key: [$1]  Value:[$2]"));

Ten regexp s sklada z dvoch casti oddelenych ciarkou; Kazda z nich matchne string tvaru "nieco", kde nieco je postupnost "znakov", pricom kazdy "znak" je bud ne-uvodzovky, alebo dvojica uvodzoviek.

Re:Regulární výraz - ne a ne opravit (C#)
« Odpověď #3 kdy: 31. 03. 2020, 10:46:04 »
Ahoj všem, dovolím si oživit starý topic. S reg. výrazy začínám a potřeboval bych validovat text na vstupu, zda neobsahuje nějaké podivné znaky. Kvůli uživatelským chybám i kvůli bezpečnosti. Zjednoduším na tento příklad:

Řetězec nesmí obsahovat nic než běžné znaky + vybranou interpunkci: [^a-zA-Z0-9\;\. ]
Ale může obsahovat znak ' pokud je před ním a za ním číslo: \d+\'\d+

Např.
adam je fajn. > ok
adam 2000 > ok
adam '200' > chyba
adam 20'20 > ok

Představa byla, že pokud mi regex nevrátí false, vím že tam "něco je". Jak tomu mám správně vysvětlit to "ale", aby prošel poslední příklad díky podmínce splňuje \d+\'\d+

Děkuju za postrčení, M.
« Poslední změna: 31. 03. 2020, 10:50:45 od Mirouss »

qelurg

  • ****
  • 382
    • Zobrazit profil
    • E-mail
Re:Regulární výraz - ne a ne opravit (C#)
« Odpověď #4 kdy: 31. 03. 2020, 11:59:29 »
Ahoj všem, dovolím si oživit starý topic. S reg. výrazy začínám a potřeboval bych validovat text na vstupu, zda neobsahuje nějaké podivné znaky. Kvůli uživatelským chybám i kvůli bezpečnosti. Zjednoduším na tento příklad:

Řetězec nesmí obsahovat nic než běžné znaky + vybranou interpunkci: [^a-zA-Z0-9\;\. ]
Ale může obsahovat znak ' pokud je před ním a za ním číslo: \d+\'\d+

Např.
adam je fajn. > ok
adam 2000 > ok
adam '200' > chyba
adam 20'20 > ok

Představa byla, že pokud mi regex nevrátí false, vím že tam "něco je". Jak tomu mám správně vysvětlit to "ale", aby prošel poslední příklad díky podmínce splňuje \d+\'\d+

Děkuju za postrčení, M.

Nejjednodušší je vysvětlit mu to jako 'nebo' tj. znak |
Kód: [Vybrat]
>>> from re import match
>>> match(r"^([a-zA-Z0-9]+|[a-zA-Z0-9]*\d+'\d+[a-zA-Z0-9]*)$", "abcdef6+'8c")


qelurg

  • ****
  • 382
    • Zobrazit profil
    • E-mail
Re:Regulární výraz - ne a ne opravit (C#)
« Odpověď #5 kdy: 31. 03. 2020, 12:18:40 »
Dalsi moznost je pouziti lookahead a lookbehind assertion.

Kód: [Vybrat]
>>> match(r"^[a-zA-Z0-9]+(?<=\d)'(?=\d)[a-zA-Z0-9]+$", "ab0'1cd")
<re.Match object; span=(0, 7), match="ab0'1cd">

To jsou ty testovaci (?=...) a (?<=...).

Re:Regulární výraz - ne a ne opravit (C#)
« Odpověď #6 kdy: 31. 03. 2020, 13:10:13 »
Tohle se tu řešilo. Závěr je, že naprogramovat výraz  pro nevýskyt něčeho je celkem obtížné. Myšleno samotný regulérní výraz a ne příkaz grep, kde inverzi řeší parametr -v a samotný r.výraz hledá výskyt.
Pokud jde jeden znak, tak to problém není. To je triviální.

Re:Regulární výraz - ne a ne opravit (C#)
« Odpověď #7 kdy: 31. 03. 2020, 14:05:52 »
Díky oběma za reakce! Bohužel o jeden znak nejde, šlo mi opravdu primárně o tu "negativní" výjimku umožňujicí použít jinak nepovolený znak pokud je v nějakém výrazu.

V mezičase jsem díky příspěvku qelurga dal do kupy zdá se fungující:

^([a-z0-9 ]|(?<=\d+)\'(?=\d+))*$

A podmínku budu mít nastavenu na !(preg_match(....)) přesně jak píšete vy. S tím, že konkrétní problematický znak/řetězec se přímo regexem nedozvím, ale budu alespoň vědět že je v řetězci něco špatně.

abc 20'20                >>> projde
abc 20'20 abc 20'20 je   >>> projde
abc 20'20'               >>> neprojde
abc 20'20'a              >>> neprojde
abc 20'20'abc20'20 je'   >>> neprojde

Uff, ale potěšilo mě, že se to opravdu dělá nesnadno :) teď se necítím tak špatně, že jsem na to dvě hodiny nemohl přijít :)
« Poslední změna: 31. 03. 2020, 14:08:08 od Mirouss »

Re:Regulární výraz - ne a ne opravit (C#)
« Odpověď #8 kdy: 31. 03. 2020, 17:18:09 »
Regexy su zbytocny kanon na vrabce v F# to za pomoci pattern matchingu rozparsujes velmi lahko:

Pozri si tento priklad: https://github.com/AshleyF/FScheme/blob/master/FScheme.fs#L16 funkciu tokenize a v nej riadky 44 a 17.

Len pri stringoch netreba zabudnut na escapovanie.

PS: podla toho co si uviedol by to mal zvladnut aj hociaky CSV parser len ako oddelovac treba nastavit ciarku.

qelurg

  • ****
  • 382
    • Zobrazit profil
    • E-mail
Re:Regulární výraz - ne a ne opravit (C#)
« Odpověď #9 kdy: 31. 03. 2020, 20:42:55 »
Jednoduchý regex je kanón na vrabce a odkážeš ho na zdroják, který má cca 500 řádků kódu?  Některým lidem fakt nerozumím.

Re:Regulární výraz - ne a ne opravit (C#)
« Odpověď #10 kdy: 31. 03. 2020, 22:08:26 »
Jednoduchý regex je kanón na vrabce a odkážeš ho na zdroják, který má cca 500 řádků kódu?  Některým lidem fakt nerozumím.

Ten jednoduchý regex testuje metódou pokus / omyl a stále si nie je istý čo mu naozaj odtiaľ vylezie. No najvačší fail je že sa to potom ťažko ladí a rozširuje. Mne to príde dosť nekoncepčné.

Tuná je moje riešenie:

https://pastebin.com/HtDt3Wgf

Vo vnútri stringového literálu môže byť aj čiarka, podporuje to escapovanie takže si doň môže vložiť úvodzovku (\") alebo ak chce vložiť lomítko tak takto \\, taktiež podporuje viac ako dve hodnoty na jednom riadku a vie tým získať aj hodnoty z viacerých riadkov. A celé sa to dá jednoducho rozširovať o novú syntax.

qelurg

  • ****
  • 382
    • Zobrazit profil
    • E-mail
Re:Regulární výraz - ne a ne opravit (C#)
« Odpověď #11 kdy: 31. 03. 2020, 23:00:50 »
Jednoduchý regex je kanón na vrabce a odkážeš ho na zdroják, který má cca 500 řádků kódu?  Některým lidem fakt nerozumím.
Ten jednoduchý regex testuje metódou pokus / omyl a stále si nie je istý čo mu naozaj odtiaľ vylezie. No najvačší fail je že sa to potom ťažko ladí a rozširuje. Mne to príde dosť nekoncepčné.
Protože jim nerozumí. Stejným způsobem může testovat metodou pokus omyl tvůj 40 řádkový výtvor, který nahrazuje jeden řádek regexpu. Regexpy nejsou žádná magie, je to jazyk jako každý jiný a buď ho umíš nebo ne. Stejným způsobem jsem si dělal SQL dotazy, aby mi vracely výsledky, které jsem potřeboval. Po půl roce se mi to také těžko měnilo, protože už jsem to zase nechápal. Ale to neznamená že SQL je špatný, to znamená, že to s ním efektivně neumím (a jednodušší by pro mě bylo načíst si to všechno a vyfiltrovat to až na aplikačním serveru). Takže ano, neznalost regexpu mohu obcházet tímto způsobem, ale přijde mi to dost neproduktivní u tak jednoduchých věcí.

BoneFlute

  • *****
  • 1 983
    • Zobrazit profil
Re:Regulární výraz - ne a ne opravit (C#)
« Odpověď #12 kdy: 01. 04. 2020, 01:02:57 »
Jednoduchý regex je kanón na vrabce a odkážeš ho na zdroják, který má cca 500 řádků kódu?  Některým lidem fakt nerozumím.

Ten jednoduchý regex testuje metódou pokus / omyl a stále si nie je istý čo mu naozaj odtiaľ vylezie. No najvačší fail je že sa to potom ťažko ladí a rozširuje. Mne to príde dosť nekoncepčné.

Tuná je moje riešenie:

https://pastebin.com/HtDt3Wgf

Vo vnútri stringového literálu môže byť aj čiarka, podporuje to escapovanie takže si doň môže vložiť úvodzovku (\") alebo ak chce vložiť lomítko tak takto \\, taktiež podporuje viac ako dve hodnoty na jednom riadku a vie tým získať aj hodnoty z viacerých riadkov. A celé sa to dá jednoducho rozširovať o novú syntax.

Teda jako, musím uznat, že je to inspirativní. Budu z toho čerpat. Na druhou stranu psát na dotyčného zadání tokenizer mi přijde poněkud přehnané, nemyslíš? Ale věřím, že tě to bavilo :-)

Re:Regulární výraz - ne a ne opravit (C#)
« Odpověď #13 kdy: 01. 04. 2020, 01:47:48 »
String.Split() ?

Re:Regulární výraz - ne a ne opravit (C#)
« Odpověď #14 kdy: 02. 04. 2020, 10:40:30 »
Díky všem za reakce i za návrhy alternativního řešení! Osobně jsem nakonec zůstal u regulárních výrazů, protože cílem bylo jednoduše ověřit shodu řetězce za použití složitějších podmínek než je prostá kontrola znaků (odchytávám například správnost formátu GPS souřadnic apod.), na což mi regex přijde jako ideální.

Jako začátečníkovi mi nakonec hodně pomohly tři věci: nesnažit se o negativní podmínku :) což bylo asi hlavní, nesnažit se naprogramovat vše rovnou regexu ale brát to jen jako vstup a pracovat s celým řetězcem pomocí ^ a $ a nesnažit se jet vše na úrovni znaků.

Každopádně myslím došlo k prozření, takže už to běhá a mám vyřešeno a další jednoduší kontroly začínám bušit od pasu :) ještě jednou díky všem za pomoc!