Egy bizonyos feladat kapcsán le kell cserélnem bizonyos kifejezéseket másra.
Ehhez lenne egy kis segítségre szükségem, ugyanis a következő regexp jelenlegi formájában működik,de akárhogy próbáltam bővíteni valahogy nem jött össze a dolog:
\#\{[\w\W&&[^\}]]*\}
erre működik:
\s#{attribute="\w+"="#{value="\w*"}"
erre nem (megáll az első }-nél):
\s#{attribute="\#\{\w+\\\}"="#{value="\w*"}"
Nem vagyok egy regexp guru, neten kerestem, lehet hogy én vagyok a béna, de sok mindent nem találtam.. 2 órája szenvedek..
valaki valamit tud hozzá tenni? akár tutorialok is..
(példafájl: http://boobekdev.fw.hu/TextModifier.java )
- 2065 megtekintés
Hozzászólások
egy jótanács: ha (java) programozásban elakadsz és kérdezel, akkor csatolj egy egyszerű (<100 sor) példaprogramot is, mert így szokás, és mert így jó ;)
szóval a programod így néz ki kb?
String orig = "\\s#{attribute=\\#\\{\\w+\\\\\\}=#{value=\\w*}";
String regExp = "\\#\\{[\\w\\W&&[^\\}]]*\\}";
String output = orig.replaceAll(regExp, "YO");
System.out.println(output);
?
így
\sYO=YO
az output, ami jó (nem hozza a "(megáll az első }-nél)" bugot)
- A hozzászóláshoz be kell jelentkezni
Köszi a gyors választ, és a tippet;)
úgynéz ki elírtam a "példámat"..
bemásoltam ide egy példaprogramot:
http://pastebin.com/m5e007211
(frissítve: itt a java fájl: http://boobekdev.fw.hu/TextModifier.java )
Az outputja nálam:
orig: #{attribute="\#\{\w+\\\}ez meg a YOban van"} #{value=\w*}
regexp: \#\{[\w\W&&[^\}]]*\}
output: YOez meg a YOban van"} YO
És azt szeretném, hogy az "ez meg a YOban van"}" rész még YOban legyen!:) Ez a problémám.
- A hozzászóláshoz be kell jelentkezni
Lehet, hogy egyszerűbb lenne, ha leírnád, mire is szeretnéd használni, mert nem teljesen világos...
Soha nem dolgoztam javában, így nem is nagyon találkoztam osztályhalmaz-műveletekkel, épp ezért fogalmam sincs, hogy a
[ab&&[^c]]
jelentése "a vagy (b és nem c)" vagy "(a vagy b) és nem c".
Abban viszont biztos vagyok, hogy a
[\w\W]
bármire illeszkedik.
Ha leírod, pontosan mit is szeretnél keresni, esetleg alátámasztod egy-két elvárt input/output párossal, sokkal könnyebb válaszolni a kérdésre.
- A hozzászóláshoz be kell jelentkezni
Rendben:
van ugye pl a html.. erre épül java EE-ben a jsp. Nos ez a körítés, lényegében annyi, hogy a HTML-ben általában csak betűk és számok helyezkednek el egy kifejezésben, addig jsp-ben nem.
Nos annyi a lényeg, hogy írok egy kis programot, és ahhoz egy minimális scriptnyelvet, és úgy terveztem, hogy a "#{" nyitótaggal lehetne kezdeni a szkriptet a kódban és "}"-el zárni. Nos egy a probléma, hogy a scriptben -a terveim szerint- szerepelni fog egy attributum mező (fentebb attribute) és a hozzátartozó value. Az attributum mező csak angolbetüket tartalmazhat, a value mező meg sok mást:) mint pl reguláris kifejezést, ami meg mindent tartalmazhat..
körülbelül így nézne ki:
#{attribute="xz"} #{value="xy"}
ahol xz helyébe csak angol betük, míg xy helyére akár ilyen szöveg is jöhet, mint pl "#{document.parser.id}".
És itt kezdődik a probléma, ugyanis nem tudom hogy hogyan kéne megoldani azt, hogy ne lépjen ki ennél a résznél... (idézőjelben sem bízok, mert az is lehet a kifejezésben)
Összefoglalva azt szeretném, hogy egy reguláris kifejezéssel szövegből kinyerni a #{xy="zv"} kifejezéseket, ahol xy betűkből áll, zv pedig bármiből.
- A hozzászóláshoz be kell jelentkezni
Rengetegszer van szükségem hasonlóra, így egy egyszerű javaslat: használj olyan határoló-karaktersorozatot, ami más esetben elég valószínűtlen, hogy előfordul.
Legyen pl. {{...}} a forma. (Én egyébként általában hármat használok :)
Ha feltételezheted, hogy egymás után két nyitó vagy záró kapcsos zárójel nem fordul elő, a regex máris baromi egyszerű:
\{\{.*?\}\}
- A hozzászóláshoz be kell jelentkezni
köszi, lehet, hogy ez lesz!
Nem szép, de működik szinte minden esetben!:)
- A hozzászóláshoz be kell jelentkezni
Röviden: Javához írsz szkriptnyelvet és azt akarod, hogy ha egy stringen belül előfordul az amit egyébként escape karakternek használsz, akkor azt ne észlelje eszkép karakternek, igaz?
Általában a regexp-pel megírt programok mind elhasalnak a kivételes stringeknél. Tipikusan a kódot állapotgéppel olvasva sokkal egyszerűbb ezen esetek kezelése, de úgy sem egyszerű.
Egyszerűbb megoldás, ha a szkriptnyelved eszkép karakterét paraméterezhetővé teszed, és mindig olyat használsz, ami a célterületen nem fordul elő.
Egyébként a szkriptnyelved nem template nyelv igazából? Biztos, hogy saját nyelvre van szükséged? Leírhatnád, hogy mit csinálsz, mert mást is érdekelhet.
- A hozzászóláshoz be kell jelentkezni
Úgy kezdődött, hogy egyetemen dolgozgatunk most éppen két projekten: egy kicsin és egy nagyon.
Én mostanában kezdem el írni a diplomamunkámat, és a "főnök", aki egy tanárom és a konzulensem feldobott pár hete egy nagyon jó diplomatémát, aminek nagyon örültem, aztán pár napra rá közölte, hogy lesznek még módosítások abban a projektben, amit a múltfélévben csináltam, kezdve onnan, hogy többnyelvűsítés, és nem biztos, hogy marad időm az eredeti diplomatervezetre.. (elméletben csak következő félévben van diplomafélévem, tehát végűlis nem hajt annyira a tatár). Ott mindössze csak 20-30 darab jsf oldalt kell többnyelvűsíteni, de előrelátóan gondolkoztam, és mivel tudom, hogy egy másik projekt (a fentebb említett nagy) is elkészül 1-2 hónap múlva, ezért úgygondoltam, hogy nem én gányolom a jsf oldalakat, hanem írok rá egy kis programot..
Első nekifutásra írtam egyet két nap alatt, ami az adott többnyelvűsítést tökéletesen megoldotta.. legeneráltam a default nyelvi fájlt, átírta a jsf-eket, generált egy lokalizációs beant.
Ezzel csak az volt a problémám, hogy elég gány, és csak egy feladatra jó.. ekkor kezdtem gondolkozni az általánosításon és azt hiszem újra feltaláltam a spanyolviaszt (mert nem kerestem sokat elötte), és elhatároztam, hogy megírom úgy a kódot, hogy az xml-ből olvassa ki a dokumentum leírását (vagyis, hogy hogyan kell értelmezni), aztán egy másik xml-ből pedig a műveletsort, amit végre kell hajtania.
és itt kell egy saját egyszerű -ha jól sejtem rosszul használtam a scriptnyelvet rá- nyelv amellyel meglehet jelölni egy-egy dokumentrész-t, és a műveletsorból hivatkozni rá..
pl egy egyszerű példa:
http://boobekdev.fw.hu/doc.xml
itt a "property" elementben használjuk, ahol azt próbálom leírni hogy egy html dokumentum tag-jei tartalmazhatnak attribútumokat, mint pl "img src=\"asd.png\" \> és itt névszerint kiszedni az src attribútumot és értékét.
azonkívül a műveletsorban hivatkozhatunk így, h
http://boobekdev.fw.hu/operations.xml (itt valamit elrontottam, de a forráson látszik szerintem, hogy mit akarok mondani)
és persze regexp használata bárhol megengedett..
Ehhez akarok írni egy "nyelvet",
de ha tudsz mondani valami szebb/jobb megoldást akár az egészre, akár erre a részre, akkor ne kímélj!:)
- A hozzászóláshoz be kell jelentkezni
Két dolgot nem értek.
Az első: ha jól sejtem, xml-fájlokat dolgozol fel. Nem lenne egyszerűbb XPath-szal keresni, egyszerűbb, nem kell mindenféle kivételekkel, határolókarakterek kerülgetésével szenvedni.
A második: biztos vagy abban, hogy tudod, miket írsz le egy-egy regexben?
A
<!--[\w\W&&[^\*/]]*-->
egyenértékű ezzel:
<!--[^*/]*-->
A
"[\w\W&&[^"]]*"
hasonlóképp ezzel:
"[^"]*"
A második eset szebben (és általában optimálisabban):
".*?"
Az elsőt viszont nem is értem. Ha HTML-commenteket akarsz vele keresni, akkor simán:
<!--.*?-->
Miért ne szerepelhetne commentben csillag vagy perjel?
A harmadik viszont húzós. A HTML-tagekre így nem kereshetsz, csak ha biztosan tudod, hogy egyik attribútum értéke sem tartalmaz nagyobbjelet. Erre a megoldás:
<[^/](?:[^">]+|".*?")+>
Ha esetleg aposztróf is szerepelhet attribútum értékhatárolóként:
<[^/](?:[^"'>]+|".*?"|'.*?')+>
Azért érdemes a tagnyitó után élből egy nem-perjelre keresni, mert a zárótagben úgysem lesz attribútum, illetve nem kezdődhet idézőjellel sem, és ahogy elnézem, zárótagre nincs szükséged.
Az utolsó regexed nem is értem, miért nincsenek escape-elve a kapcsos zárójelek, míg a hashmark igen, és még mindig nem jöttem rá, mire is akarsz keresni :)
(egy kis szerkesztés: közben rájöttem, hogy vélhetően javában a hashmark önmagában commentet jelöl)
Az összes fenti kifejezés csak singleline (dot-matches-all) módban működik!
- A hozzászóláshoz be kell jelentkezni
"Az első: ha jól sejtem, xml-fájlokat dolgozol fel. Nem lenne egyszerűbb XPath-szal keresni, egyszerűbb, nem kell mindenféle kivételekkel, határolókarakterek kerülgetésével szenvedni."
Nem, nem xml fájlokról van szó. Mint korábban írtam eredetileg csak jsp fájlokat kellett módosítanom, de úgy gondoltam próbálok írni egy általános dokumentum parserst..
-----
"A második: biztos vagy abban, hogy tudod, miket írsz le egy-egy regexben?"
nem, regexpet nem vágom még annyira, csak arra mentem, hogy működjön!:)
-------
"Miért ne szerepelhetne commentben csillag vagy perjel?"
Ez egy régebbi verziója volt a fájlnak, és itt sima /* */ java kommmentet néztem, késöbb javítottam.
-------
"A harmadik viszont húzós. A HTML-tagekre így nem kereshetsz, csak ha biztosan tudod, hogy egyik attribútum értéke sem tartalmaz nagyobbjelet."
Erre kidolgoztam egy megoldást.. Méghozzá azt a talán nem túl gyors megoldást, hogy:
A dokumentum egyes jelölőinek van egy prioritása.. vagyis, ha a html comment 1-es priorral rendelkezik a html quote 2-es priorral, akkor a következő részt csak egy commentnek értelmezi, nem egy commentnek és egy qoute-nak:
/*
almát szedtem "ridikülbe"..
*/
Ezt úgy oldottam meg, hogy a dokumentum szöveges reprezentálását lemásolom egy stringbuffer-be, és ha megtalálok egy commentet, akkor abban lehet akármi kivéve a zárótag ugye.. ezt ezután a részt a stringbufferben helyettesítem azzal a karakterrel (amit a document.xml-ben adtam meg), ami az adott dokumentumban jelentéssel nem bír.
Ez azért működik, mert egy documentElement-ben nem a szöveget tárolom, hanem a szövegkezdetének és végének helyét a dokumentum szöveges reprezentációjában.
Ez a html-tagban úgy müködik, hogy a következő elemet így bontja: input -nyito-type="text" value="alma-nyito-br-zaro"-zaro-
elsőkörben:
qoute: "text", qoute: "alma
"
ezután a következő szövegben keresek tovább:
-nyito-type= value= -zaro-
hosszra ugyanakkora, csak az idézőjeles részeket kihelyettesítettem whitespace-el.
------
A regexeket köszi, most megnézem mit hova tudok használni!
- A hozzászóláshoz be kell jelentkezni
"Erre kidolgoztam egy megoldást."
És ezt minek értelmezi?
/*
"valami */"
*/
(Az általam említett probléma természetesen nem ezt fedi, mert a */-nek emlékeim szerint a sor végén kell állnia.)
Egyébként kezdem érteni, mit akarsz csinálni. Majd ha egy kicsit több időm lesz, előkeresem egy hasonló kódomat, hogy lásd mikbe fogsz belefutni :)
- A hozzászóláshoz be kell jelentkezni
Azt megköszönném majd! Akár küldheted emailre is, ha megvan! Ígérem csak személyes engedélyeddel használok fel kódrészletet:)
amúgy amit te írtál azt nem az én értelmezőm értelmezi hibásan hanem te!
Ugyanis a fenti kódban a "valami */-al véget ér a komment!:)
Mivel a kommenten belűl sehol sem értelmezik az idézőjeleket..
mail címem: bkanyo kuk@c gmail pont com
- A hozzászóláshoz be kell jelentkezni
Szóval, amire rá akartam térni, az a regexek végrehajtási sorrendje.
Szép, hogy van prioritás az elképzelésedben, de ha ezt egy ciklussal oldod meg, akkor gondban leszel, mert hogy oldod meg, hogy a második iteráció ne az első eredményén hajtódjon végre, vagyis "ne lóghassanak egymásra" a találatok?
No, itt egy C# megvalósítás a problémára. Baromi ronda, az eredeti kódot messze nem úgy írtam, hogy publikáljam, ráadásul mire átalakítottam a példa kedvéért, kigyalulva a maradék kb. 1000 sort, még rondább lett :)
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
namespace demo
{
delegate string RegexReplace(Match m);
class Program
{
public struct RegexReplaceDefinition
{
public string RegexString;
public RegexReplace RegexReplaceMethod;
public RegexReplaceDefinition(string regex, RegexReplace regexreplace)
{
RegexString = regex;
RegexReplaceMethod = regexreplace;
}
public string GetNamedRegex(string name)
{
return "(?:(?<" + name + ">)" + RegexString + ")";
}
}
static void Main(string[] args)
{
Dictionary<string, RegexReplaceDefinition> regexlist = new Dictionary<string, RegexReplaceDefinition>();
regexlist.Add("elso", new RegexReplaceDefinition(@"elso", delegate(Match m) { return "ELSO"; }));
regexlist.Add("masodik", new RegexReplaceDefinition(@"masodik", delegate(Match m) { return "MASODIK"; }));
StringBuilder sbFullRegex = new StringBuilder();
foreach (KeyValuePair<string, RegexReplaceDefinition> kvp in regexlist)
sbFullRegex.Append(kvp.Value.GetNamedRegex(kvp.Key)).Append('|');
sbFullRegex.Length--;
string test = "nulladik elso masodik harmadik";
test = Regex.Replace(test, sbFullRegex.ToString(), delegate(Match m)
{
foreach (string name in regexlist.Keys)
{
if (m.Groups[name].Success)
return regexlist[name].RegexReplaceMethod(m);
}
return m.Value;
}, RegexOptions.Compiled);
Console.WriteLine(test);
}
}
}
A struct azért van, mert így sokkal egyszerűbb bánni az egésszel (az eredeti kód egyetlen osztályban oldja meg a dolgot, de abban futásidejű C# fordítás és hasonlók vannak, ezért most a példához írtam csak a Main()-t).
Esetedben természetesen a definíciós XML-ből kell olvasni az adatokat a regexlisthez.
A Dictionary "nevesítve" tartalmazza az egyes definíciókat. A definíciók két dologból állnak: a keresőkifejezésből, illetve a cserét lebonyolító függvényből.
A cserét lebonyolító függvényt én speciel config-fájlból szedem, és futásidőben fordíttatom le, de ez most érdektelen, mert fogalmam sincs, hogy lehet-e ilyet csinálni javában, és ha igen, hogyan. A lényeg, hogy egy Match objektumot vár, és egy stringet kell visszaadnia, ez gondolom javában is hasonló.
Miután összeszedted az összes kifejezést, a StringBuildert (lehetne string is, de .NET-ben így gyorsabb) feltöltő ciklus összefűzi az egyes kifejezéseket, egy pipe-pal elválasztva (az utolsót persze leszedi). A GetNamedRegex() a trükk: egyrészt nem gyűjtő zárójelbe teszi a kifejezést, másrészt az elejére beszúrja a keresőkifejezés "nevét".
Most jön maga a csere, ami most már egyetlen regexet használ, az összes egyedi kifejezést prioritási sorrendben egymás után (ha az első teljesül, tovább nem megy). A cserekifejezés egy helyben definiált függvény, ami végigmegy a neveken, és ha megtalálja az ilyen nevű csoportot, akkor meghívja a hozzá tartozó cserélő függvényt. Ha nincs találat – ami elméletileg nem fordulhat elő, ha az egyes regexek hibátlanok –, akkor visszadja magát a találatot (normálisan egyébként exceptiont kéne dobni.)
Korlátok:
- Ha jót akarsz, csak nevesített csoportokat használsz a keresőkifejezésekben, a számozott csoportok ilyen esetben vagy jól (elvárt módon) működnek, vagy nem.
- Vigyázni kell, hogy ne használj a regexekre olyan nevet, mint amilyen nevű csoport bármelyikben előfordul, mert nagy gebasz lesz belőle.
- Ha bármilyen opciót megadsz a regexmotornak (.NET-ben pl. SingleLine stb.), az az összesre igaz.
- Az egyes regexkifejezéseknek önmagukban zártnak kell lenniük, tehát kerülendő pl. a
(?s)...(?-s)
használata, mert fogalmam sincs, hogy mi történik a hatásával a pipe után, helyette viszont jó (ha a motor ismeri) a
(?s:...)
kifejezés.
Ha valami nem tiszta, szólj.
- A hozzászóláshoz be kell jelentkezni
Nem feltétlenül hasal el a regex, legfeljebb nem minden esetben optimális. (Engem nem érdekel, bármire képes vagyok regexet használni :)
Semmi gond pl., ha a backslash minden esetben escape-ként értelmezendő:
\{\{(?:\\.|.)*\}\}
Ennek két szépséghibája van: csak singleline módban megy, illetve feleslegesen terheli a motort. Persze némiképp bonyolultabban máris jóval gyorsabb:
\{\{(?:[^\\]+|\\.)*\}\}
Az igazán optimális természetesen az lenne, ha csak a két záró kapcsos előtt kéne vizsgálni, hogy nem áll-e páratlan számú backslash, de ez macerás, mert a következőn szerintem minden második regexmotor elhasal (pl. a perl is csak fix karakterhosszra enged utóvizsgálatot):
\{\{.*?(?<=[^\\](?:\\\\)*)\}\}
- A hozzászóláshoz be kell jelentkezni
echo '#{attribute="\#\{\w+\\\}ez meg a YOban van"} #{value="\w*"}' |perl -ne 'print "Attrib:$1\nValue:$2\n" if m/#\{attribute="(.*)"\}\s+#\{value="(.*)"\}/'
kimenet:
Attrib:\#\{\w+\\\}ez meg a YOban van
Value:\w*
orig: #{attribute="\#\{\w+\\\}ez meg a YOban van"} #{value="\w*"}
regexp: #\{attribute="(.*)"\}\s+#\{value="(.*)"\}/
Pontosabban ?
Az jo -e neked amit most ez a perl csinal ?
Amit nem lehet megirni assemblyben, azt nem lehet megirni.
- A hozzászóláshoz be kell jelentkezni
úgy látom igen, köszönöm!
Csak ennyi lett volna a problémám szerintem, de ezt a kódot nem teljesen értem sajnos!
A print az oké, de ami utána következik azt nem tudom, hogy pontosan hogy és mi.
A problémát megpróbálom még egyszer körülírni:
- adott egy sztring.
- a sztring tartalmazhat egyszerre reguláris-kifejezéseket és az általam definiált kifejezéseket.
- először a sztringet odavetem az én feldolgozókódomnak, ami aztán szétszabdalja a sztringet reguláris-kifejezésekké és általam definiált kifejezésekké.
Az hogy milyen karakterrel választom el a saját utasításokat a regexp-ektől az lényegében mindegy, bár olyat akartam használni, amit már a regexp is használ, hogy ne kelljen még több escape karaktert használni.
- A hozzászóláshoz be kell jelentkezni
Ha atirom javara az segit ?
echo '#{attribute="\#\{\w+\\\}ez meg a YOban van"} #{value="\w*"}'|
Ez ugye betolja az input stringet az stdin -re
perl -ne
Ez perl interpretert hivja:
-e vedd a kodot a paracssorbol
-n tegy a kod kore egy while ciklust, ami a bemenet minden sorara vegrehajtja a magot
print "Attrib:$1\nValue:$2\n"
Ugye ez a kiiras, a $1 az elso zarojelbeli dolgok, a $2 a masodik zarojelek kozott levo regularis kifejezesre illeszakedo minta darab.
if
A tole balra levo dolgot akkor hajtja vegre, ha a tole jobbra levo kifejezes igaz, esetunkben, ha a minta illeszkedik akkor kiirunk.
m/#\{attribute="(.*)"\}\s+#\{value="(.*)"\}/'
Regularis minta illesztes perlben (m//), ha nem adom meg mire akor "$_" -ban levo sztingre ($_ =~ m// ), ami esetunkben a bemenet egy-egy sora.
Amit nem lehet megirni assemblyben, azt nem lehet megirni.
- A hozzászóláshoz be kell jelentkezni
valaki?
- A hozzászóláshoz be kell jelentkezni