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.

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.

Gábriel Ákos

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.

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)]