Regexp magus van itt? :)

parsolnom kene ilyen parametereket:

param1=abc

param2 = abc

param3 = "ab'c"

param4='a"b"c'

param5="abc=def"

egyaltalan megoldhato ez egy regexp-el? (most karakterenkent dolgozom fel...)

lenyeg hogy lehet ' es " is az idezojel (de nem is kotelezo) es azon belul a masik fajta idezojel sima karakterkent mukodik.

es akkor meg a \' nem is neztuk, de az talan nem is kell.

pythont hasznalok, ami elvileg perl regex kompatibilis nagyjabol...

Hozzászólások

Szerkesztve: 2023. 12. 02., szo – 19:00

Ha jól értem: [abc\'\"]{3,5}

param5-nél mi a  terv? kiértékelni?

nem jol erted...

kb ez kene legyen az output:

param1=abc

param2=abc

param3=ab'c

param4=a"b"c

param5=abc=def

tehat a folosleges whitespacet (= elott/utan) es az idezojeleket kene eltuntetni, param neve es az ertek kellene belole, barhogy is irtak.

Ez esetleg?

/^(\w+)\s?=\s?(['\"]?)(\S*)\2$/gm

 

https://regex101.com/r/hbsISt/1

így elvileg \1 és \3 tartalmazza a lényeget (bár lehet van ennél szebb forma, de most hirtelen ezt találtam)

szuper, koszi!  remlett hogy valahol lattam olyat hogy lehet matchelni masik matchre de nem igazan talaltam/ertettem hogyan...

kicsit kibovitettem igy elvileg az opcionalis tovabbi parametereket meg berakja \4-be:

^(\w+)\s?=\s?(['\"]?)(.*?)\2\s?(;.*)?$

pl:  param1="a bc"; param8=efg; param9="aaa"

https://regex101.com/r/3UXWPt/1

szerk: kezdek belejonni, igy mar a \" sem problema:

^\s*(\w+)\s*=\s*(['\"]?)((?:\\.|.)*?)\2\s*(;.*)*$

param3 =  " ab'\"; c"  ; p23=55

ugyanakkor nem vagyok meggyozodve rola, hogy ez igy gyorsabb, mint karakterenkent vegigmenni rajta (for ciklus + state machine)...

Ilyesmire gondolsz?

#!/usr/bin/env python3

import re

pattern = r"(?P<variable>[_a-zA-Z][_a-zA-Z0-9]*)\s*=\s*(?P<value>\"[^\"]*\"|'[^']*'|[^ '\"]*)"
test_list = '''param1=abc
param2 = abc
param3 = "ab'c"
param4='a"b"c'
param5="abc=def"'''.split("\n")

for test_case in test_list:
  res=re.match(pattern, test_case)
  print(f"{test_case=}: {res['variable']=} {res['value']=}")

test_case='param1=abc': res['variable']='param1' res['value']='abc'
test_case='param2 = abc': res['variable']='param2' res['value']='abc'
test_case='param3 = "ab\'c"': res['variable']='param3' res['value']='"ab\'c"'
test_case='param4=\'a"b"c\'': res['variable']='param4' res['value']='\'a"b"c\''
test_case='param5="abc=def"': res['variable']='param5' res['value']='"abc=def"'

Azt nem specifikaltad, mi a teendo, ha nincs macskakorom, csak elkezded irni a dolgot

A strange game. The only winning move is not to play. How about a nice game of chess?

Jogos

#!/usr/bin/env python3

import re

pattern = r"(?P<variable>[_a-zA-Z][_a-zA-Z0-9]*)\s*=\s*(?:\"(?P<value1>[^\"]*)\"|'(?P<value2>[^']*)'|(?P<value3>[^ '\"]*))"
test_list = '''param1=abc
param2 = abc
param3 = "ab'c"
param4='a"b"c'
param5="abc=def"'''.split("\n")

for test_case in test_list:
  res=re.match(pattern, test_case)
  value=res['value1'] or res['value2'] or res['value3']
  print(f"{test_case=}: {res['variable']=} {value=}")

A strange game. The only winning move is not to play. How about a nice game of chess?

Regex megoldást írtak fentebb, viszont én hasonló esetben inkább egy protobuf/json/yaml/akármi fájlt olvasnék be, és akkor ingyen van hozzá parser, ami a trükkösebb dolgokat is kezeli (escape karakterek meg ilyesmi) és a felhasználó is ismerni fogja a formátumot. Még a shell is lehet jó, pl. A=12 B="3 4" C=$(date) programom.py vagy programom.py --a=12 --b="3 4" --c=$(date).

Ha sajat programhoz tartozo configfile, akkor +1 erre. Ezt viszont nem irta.

Ha letezo fileformatum, akkor nem annyira jo otlet, mert hoz magaval minden egyebet. Kiveve persze, ha pont a megfelelo formatum parseret talalod meg.

Ha valami egzotikus program configjat kell parse-olni amiben "a=5" jellegu sorok vannak, nem jo otlet rakuldeni pl. egy ini file parsert, csak mert az is megeszi ezeket a sorokat.

Olyan is lehet, hogy pont a configokat akarja kijavitani egy masik program szamara. (multkor jpeg kepek hibait kereste)

A strange game. The only winning move is not to play. How about a nice game of chess?

Option 1: Go use the python-mimeparse third-party library.

hat amit 10 sorban vagy 1 regexpel meg lehet irni arra nem hasznalnek kulso fuggoseget

raadasul (beleneztem a forrasaba) ez is a  cgi.parse_header(mime_type)-t  hasznalja:

Option 2: use cgi.parse_header

As of Mar 2023, the current official way of doing this, now that cgi is deprecated

using email.message.Message

epp ettol probalok szabadulni...

(\w+)\s*=\s*(".*?"|'.*?'|\w+)
 

  • (\w+) - Elkapja a paraméter nevét, ami betűkből és számokból állhat.
  • \s*=\s* - Megkeresi az egyenlőségjelet, amely előtt és után tetszőleges számú szóköz állhat.
  • (".*?"|'.*?'|\w+) - Elkapja a paraméter értékét, amely idézőjelek között állhat (akár egyszeres, akár dupla idézőjelek között), vagy csak simán szöveg lehet (számokkal és betűkkel).
(\w+)\s*=\s*(?:(?:"([^"]*)"|'([^']*)'|([^;\n"']+))\s*(?:;|$))

Most elolvastam a közbenső igényeket is, és itt tesztelhető: https://regex101.com/r/KmWmNf/3

A magyar leírás benne van a linkben is archiválás céljából.

 

  1. (\w+) - Elkapja a paraméter nevét.
  2. \s*=\s* - Keresi az egyenlőségjelet a felesleges szóközökkel együtt.
  3. (?:"([^"]*)"|'([^']*)'|([^;\n"']+)) - Elkapja az értéket a következő feltételekkel:
  4. "[^"]*": Dupla idézőjelek közötti szöveget, ami nem tartalmaz további dupla idézőjeleket.
  5. '[^']*': Egyszerű idézőjelek közötti szöveget, ami nem tartalmaz további egyszerű idézőjeleket.
  6. [^;\n"']+: Szöveget, ami nem tartalmaz sem pontosvesszőt, sem sorvégét, sem idézőjelet.
  7. \s*(?:;|$) - Keres egy opcionális sorvégi vagy pontosvessző elválasztót.

Jobb oldalt van a kiértékelés. A megoldásoddal különböző group-ba kerül be a param_value. Ez nem gond?

Én abból indultam ki, hogy jobb lenne kapni m x n-es tömböt, ami nálam n=3 volt,  n[0] => param_name, n[2]  => param_value

Igen de Árpi írta hogy python, ez pedig így rakható össze:

 

import re

regex_pattern = r'(\w+)\s*=\s*(?:"([^"]*)"|\'([^\']*)\'|([^;\n"\']+))\s*(?:;|$)'

test_text = """
param1=abc
param2 = abc
param3 = "ab'c"
param4='a"b"c'
param5="abc=def"
param6=abc; param7="hello'
param8='Itt; a vége'
"""

matches = re.finditer(regex_pattern, test_text, re.MULTILINE)

result = []
for match in matches:
    # Paraméter neve és értéke
    param_name = match.group(1)
    param_value = match.group(2) or match.group(3) or match.group(4)

    # Eredmény hozzáadása a listához
    result.append(f"{param_name}={param_value}")

result

És a tömb:

 

['param1=abc',
 'param2=abc',
 "param3=ab'c",
 'param4=a"b"c',
 'param5=abc=def',
 'param6=abc',
 'param8=Itt; a vége']

na csinaltam benchmarkot:

for: az en regi for ciklusos state-machine-szeru megoldasom
re1: Atis89 verzioja alapjan, re2: FeriX verzioja alapjan

python3.10:
for: 0.9218964576721191
re1: 0.2517125606536865
re2: 0.17335128784179688

python3.11:
for: 0.5490951538085938
re1: 0.2325422763824463
re2: 0.16354846954345703

pypy3.10:
for: 0.08430266380310059
re1: 0.15888285636901855
re2: 0.07618188858032227

erdekes hogy pypy-vel a for ciklus beelozte az egyik regexpet is...

400k mintan futott, elotte addig reszeltem a regexpeket mig egyforma lett a kimenetuk...

http://thot.banki.hu/arpi/rerere/

koszi mindnekinek az otleteket!

Egészségedre :-) Ebben a topikban az a vicces számomra hogy ugyan abból a megfontolásból pénteken nem használtam egy NodeJS csomagot, ami miatt Te se csak egy funkcióra, csak azért hogy kommenteket írhassak a JSON fájlba. Inkább írtam egy reguláris kifejezést és parzolás előtt lefuttattam hogy, eltávolítsam kommenteket:

/\/\/.*$|^\s*\/\/.*$/gm;

Ez a regex kifejezés minden olyan sort eltávolít a JSON szövegből, amely //-al kezdődik, legyen az a sor elején vagy a végén.

OT

Én csak azt nem értem, hogy miért van itt két alternatíva? Az első fele illeszkedik a sor végén álló megjegyzésekre - pl. egy utasítás mögött, de kihagyja a megjegyzés előtt a szóközöket. A második fele azokkal a sorokkal foglalkozik, ahol az egész sor csak megjegyzés - de a sor elején levő white space-ekre is illeszkedik. Miért nem jobb egyszerűsíteni egyetlen mintára, ami mindig illeszti a megjegyzés előtti szóközöket is?

/\s*\/\/.*$/gm;

/OT

Leírom nehogy valakit félrevezessen: az onnantól (hogy van benne komment) már nem szabályos JSON file azt tudjuk ugye?

Most utánaolvasva van egy érdekes gyakorlat: emberünk belerakja "_comment" mezőbe a kommentárját, attól az json marad, sőt akár ki is olvashatja feldolgozáskor ha akarja.

zászló, zászló, szív

Nekem ez egy konfiguráció, leíró, minden is JSON, ami privát fejlesztésben található, de hívjuk majdnem JSONC-nek. Én is tudom, hogy hogyan kell elkülöníteni aláhúzással azt amit ideiglenesen el szeretnék távolítani, de az olvasása közben, a látványban nem feltűnő elkülönítés. Az én szememnek a komment a kényelmes.

ott az eltérés hogy az első variáns az "bárhol kezdődő // -re" matchel és bármi lehet előtte, nem csak whitespace.

Ez szerintem veszélyes konstrukció amúgy mert semmi se zárja ki hogy a normál adatban legyen // akárhol egy string közepén.

zászló, zászló, szív

Terveztem hogy lesz benne url, hiszen a dupla per a világ legelterjedtebb ismétlődő karaktere :-) a két t betű után.

Meg ugye elég sok kérdést felmerül, például az escape / \//, stb, meg hogy aposztróf között is lehet, meg még ki tudja mi jön majd fejlesztés közben.

De az a szerencse hogy bővíthető:

https://regex101.com/r/MJXFAx/1

nezegettem azt is, de a lenyegi resze (opcionalis idezojel matchelese) ugyanaz volt, vagy nem vettem eszre valamit?

vagy arra gondolsz hogy ez csak az elso parametert matcheli, nem a (param)=(value) ; (tobbi)-t es igy maskepp lehet ciklusozni (for in matches, es nem pedig while-al amig van tobbi)?

kicsit moddoltam, igy mar jo eredmenyt ad mindenre (sajnos a param neveben lehet - es * is, meg szamok is):

https://regex101.com/r/l0Anq0/1

viszont eddig ez a leglassabb regex :(  bar meg igy is 3x gyorsabb python3.10-el (2x 3.11-el) mint a karakterenkenti for

osszekombinaltam a masikkal is, pypy-vel az lett a leggyorsabb:

https://regex101.com/r/CyIdTD/1

python3.10:

for:  0.9325275421142578      A'rpi (for karakterenkent)
re1:  0.24773311614990234   Atis89
re1f: 0.30788111686706543   gazsiazasz
re2:  0.1703355312347412     FeriX
re2f: 0.20905804634094238   FeriX+gazsiazasz

python3.11:

for:  0.5474085807800293
re1:  0.23268747329711914
re1f: 0.2706611156463623
re2:  0.16312909126281738
re2f: 0.18561649322509766

pypy3.10:

for:  0.08565855026245117
re1:  0.1592862606048584
re1f: 0.17911410331726074
re2:  0.07767152786254883
re2f: 0.07328653335571289

http://thot.banki.hu/arpi/rerere/

Mr. Elvesziamunkánkat szerint:

 

import re

# A regex minta a különböző formátumú paraméterértékek illesztéséhez
pattern = r'(?<=\=)\s*(".*?"|\'.*?\'|[^\s]+)'

# Példa sztringek a regex minta teszteléséhez
test_strings = [
    "param1=abc",
    "param2 = abc",
    "param3 = \"ab'c\"",
    "param4='a\"b\"c'",
    "param5=\"abc=def\""
]

# A regex minta alkalmazása minden tesztsztringre, és az egyezések kinyerése
extracted_values = [re.search(pattern, s).group(0) for s in test_strings if re.search(pattern, s)]