Fórum Root.cz
Hlavní témata => Vývoj => Téma založeno: gleng 05. 01. 2022, 13:02:13
-
Mam retazec ktory ma v sebe vyrazy ktore potrebujem najst a nahradit. Priklad:
@john and @johnathan went to see @sarah in their #hometown to look at her new #home.
Priklad vyrazov:
let handles = ["john", "johnathan", "sarah"]
let topics = ["home", "hometown"]
A chcem nahradit handles s <a href="/user/john">@john</a>
a topics s <a href="/topic/hometown">#hometown</a>
.
Potrebujem najst a nahradit vyrazy bez ohladu na velkost pismen a taktiez potrebujem ignorovat vyrazy ktore nie su v zozname. Dalej potrebujem zarucit ze ked sa mi prekryvaju tokeny(john -> johnathan) tak sa vyrazy najdu a nahradia spravne.
Ako by ste to napisali?
-
Seřadit tokeny od nejdelšího po nejkratší a pak jeden po druhém nahrazovat.
-
Seřadit tokeny od nejdelšího po nejkratší a pak jeden po druhém nahrazovat.
ano, a skoncis v nekonecnej slucke...
<a href="/user/john">
<a href="/user/john">
<a href="/user/john">
<a href="/user/john">...</a>
</a>
</a>
</a>
Keby to bolo take lahke tak sa tu nepytam.
-
Obecně řešení pana Jirsáka není dobře (v textu nahradím řetězec X za Y, čímž v něm vznikne řetězec Z, který je v seznamu tokenů pro další zpracování).
V tomto konkrétním případně by se to dalo asi bezpečně ošetřit.
Pro Python se mi zdá OK:
https://stackoverflow.com/a/15448887
Otázka je, jak text vypadá a jestli lze skutečně použít takto jednoduché řešení.
-
SO odpoved ak by niekto potreboval do buducna:
var tmpString = `@john and @johnathan went to see @sarah in their #hometown to look at her new #home.`,
handles = ["john", "johnathan", "sarah"],
topics = ["home", "hometown"];
console.log(tmpString);
for(var i = 0; i < handles.length; i++) tmpString = tmpString.replace(new RegExp(`(@${handles[i]})+(?![A-Za-z0-9])`, 'gmi'), `<a href="/user/${handles[i]}">@${handles[i]}</a>`);
console.log(tmpString);
for(var i = 0; i < topics.length; i++) tmpString = tmpString.replace(new RegExp(`(#${topics[i]})+(?![A-Za-z0-9])`, 'gmi'), `<a href="/topics/${topics[i]}">#${topics[i]}</a>`);
console.log(tmpString);
-
Seřadit tokeny od nejdelšího po nejkratší a pak jeden po druhém nahrazovat.
ano, a skoncis v nekonecnej slucke...
<a href="/user/john">
<a href="/user/john">
<a href="/user/john">
<a href="/user/john">...</a>
</a>
</a>
</a>
Keby to bolo take lahke tak sa tu nepytam.
Na tohle existují specializované algoritmy, například Aho-Corasickové, které pracují v optimálním čase. Na VŠ se zrovna tento bere hned v prváku.
-
SO odpoved ak by niekto potreboval do buducna:
Než jsem vám stihl odpovědět, že máte neúplné zadání, tak jste si našel odpověď. Zrada, proč vaše zadání nebude fungovat je nejasná definice chování replace. Ono #home je substringem #hometown a tudíž by se to nejspíš mělo zacyklit. Tak zní zadání.
Vámi postnuté řešení je elegantní a funkční, protože jste do něj doplnil chybějící podmínku. A sice, že za tokenem následuje znak, co není písmenem ani číslicí. Tohle je to, čím jste zadání doplnil a problém vyřešil: (?![A-Za-z0-9])
Od té chvíle se vám #home a #hometown budou chovat jako dva různé tokeny. Ovšem jde o jiné chování než vaše původní zadání, kupříkladu nebude reagovat na #homeless, ačkoliv tam #home zcela zjevně je.
-
SO odpoved ak by niekto potreboval do buducna:
var tmpString = `@john and @johnathan went to see @sarah in their #hometown to look at her new #home.`,
handles = ["john", "johnathan", "sarah"],
topics = ["home", "hometown"];
console.log(tmpString);
for(var i = 0; i < handles.length; i++) tmpString = tmpString.replace(new RegExp(`(@${handles[i]})+(?![A-Za-z0-9])`, 'gmi'), `<a href="/user/${handles[i]}">@${handles[i]}</a>`);
console.log(tmpString);
for(var i = 0; i < topics.length; i++) tmpString = tmpString.replace(new RegExp(`(#${topics[i]})+(?![A-Za-z0-9])`, 'gmi'), `<a href="/topics/${topics[i]}">#${topics[i]}</a>`);
console.log(tmpString);
lze to udělat i takhle:
const regex_topics = /#([a-zA-Z0-9_]+)/ig
const regex_handles= /@([a-zA-Z0-9_]+)/ig
let text = "@john and @johnathan went to see @sarah in their #hometown to look at her new #home."
const handles = ["john", "johnathan", "sarah"]
const topics = ["home", "hometown"]
function createAnchor(url, text) {
let c = document.createTextNode(text);
let a = document.createElement('a');
a.setAttribute("href", url);
a.appendChild(c);
return a.outerHTML;
}
text = text.replace(regex_topics, function(value) {
let i = topics.indexOf(value.substring(1).toLowerCase())
if (i>-1) {
return createAnchor("/topic/"+topics[i], value)
} else {
return value
}
});
text = text.replace(regex_handles, function(value) {
let i = handles.indexOf(value.substring(1).toLowerCase())
if (i>-1) {
return createAnchor("/user/"+handles[i], value)
} else {
return value
}
});
Vyhneš vyhledávání přes regulární výraz ve smyčce, drahýmu dopřednými hledání, stejně tak mám ošetřené escapování a vstupní hodnoty, do url dosazuji vždy variantu s malými znaky (v tvém řešení se ti budou velká písmena přepisovat i do url).
-
SO odpoved ak by niekto potreboval do buducna:
Na test "konce slova" v regexu je \b.
Ovšem jde o jiné chování než vaše původní zadání, kupříkladu nebude reagovat na #homeless, ačkoliv tam #home zcela zjevně je.
On ale nechce homeless detekovat jako home.
-
ano, a skoncis v nekonecnej slucke...
<a href="/user/john">
<a href="/user/john">
<a href="/user/john">
<a href="/user/john">...</a>
</a>
</a>
</a>
Ne, neskončím. Když nahrazuju @john za john, nemůžu skončit v nekonečné smyčce. Dokonce neskončím v nekonečné smyčce ani při nahrazování @john ta @john, protože všechny funkce replaceAll() ve všech jazycích si vždy pamatují pozici, kde text nahradily naposledy, a pokračují dále, takže se nezacyklí.
Keby to bolo take lahke tak sa tu nepytam.
Nejkomplikovanější na tom evidentně bude zadání. Když chcete něco nahrazovat v textu, dejte sem příklad vstupu a odpovídajícího výstupu.
Pokud máte problém s tím, že chcete nahrazovat @john → xxx@johnxxx a @johnatan → xxx@johnatanxxx, ale když už jednou nahradíte @johnatana, nechcete to pak znovu nahrazovat jako @johna, pak si prostě místo nahrazování jenom zapamatujte pozice, kde se má něco nahradit, a náhradu proveďte až na konec. To zapamatování pozic je nejjednoduší udělat tak, že si vytvoříte seznam, kde se budou střídat textové části a náhrady, a v příštím kole budete nahrazovat jen v textových částech.
Začnete tedy se vstupem:
[
"@john and @johnathan went to see @sarah in their #hometown to look at her new #home.",
]
Nahradíte @johnathan:
[
"@john and ",
{replace: "@johnathan"},
" went to see @sarah in their #hometown to look at her new #home.",
]
Pokračujete náhradou @john ve zbývajících textech,
[
{replace: "@john"},
" and ",
{replace: "@johnathan"},
" went to see @sarah in their #hometown to look at her new #home.",
]
Na závěr pole projdete, texty necháte jak jsou a objekty označující náhradu nahradíte nahrazujícím textem. A pak už jen pole spojíte do stringu.
Celé to samozřejmě děláte tak, že pole nahrazovaných textů je seřazené podle délky od nejdelšího, jak jsem psal na začátku.
-
...
Zadání je naprosto jasné a tvoje řešení nesmyslně komplikované.
-
Obecně řešení pana Jirsáka není dobře (v textu nahradím řetězec X za Y, čímž v něm vznikne řetězec Z, který je v seznamu tokenů pro další zpracování).
Nenazýval bych „není dobře“ něco, co splňuje zadání. To, že zadání nespecifikovalo chování v této situaci je chyba zadání, ne řešení :-)
Než jsem vám stihl odpovědět, že máte neúplné zadání, tak jste si našel odpověď. Zrada, proč vaše zadání nebude fungovat je nejasná definice chování replace. Ono #home je substringem #hometown a tudíž by se to nejspíš mělo zacyklit. Tak zní zadání.
Kam chodíte na to zacyklení? Když mám seznam náhrad a procházím ho od začátku do konce, nemůže dojít k zacyklení, protože dojdu na konec toho seznamu náhrad. K zacyklení by mohlo dojít tehdy, pokud bych se na konci seznamu náhrad vrátil zase na začátek a začal nahrazovat vše znova (dokud v poslední obrátce došlo k nějakému nahrazování). To je ale nesmysl. Něco takového by se dělalo jedině v případě, že by se v makra v náhradách měla zase rozvinout. Ale tam je možnost zacyklení z definice a musí si to pohlídat autor těch maker (a je to špatný návrh). A kdyby to přeci jen bylo někde potřeba, omezí se tam počet zanoření maker – pokud by se mělo celé nahrazování opakovat třeba po 11, vypíše se chyba, že je možné zanořit max. 10 úrovní maker.
-
...
Zadání je naprosto jasné a tvoje řešení nesmyslně komplikované.
Ne, ze zadání nebylo jasné, čím se má nahrazovat. Dalo se chápat tak, že v textu „<a href="/user/john">@john</a >“ chce nahrazovat „@john“, „@johnathan“ a „@sarah“, ale není řečené čím – dalo by se předpokládat nějaké zobrazované jméno, přezdívka, celé jméno nebo něco takového.
Moje řešení je na pár řádek JavaScriptu. Nějak optimalizovat počet průchodů stringem nedává smysl, bavíme se o implementaci v JavaScriptu. Použití regulárních výrazů by to jen zkomplikovalo, musíte řešit escapování znaků. Navíc nic jako „hranice slova“ vám nijak nepomůže, protože nevíme nic o těch textech – jestli tam hranice slova mají nějaký význam nebo ne. Každopádně pořád je moje „komplikované“ řešení dalek olepší, než vaše neexistující řešení.
-
On ale nechce homeless detekovat jako home.
Jedině v případě, že „homeless“ i „home“ jsou v seznamu zadaných tokenů. Jinak v zadání není nic o tom, že se mají nahrazovat jen celá slova, ani nic o tom, že tokeny nemohou obsahovat mezery, pomlčky, podtržítka, znaky s diakritikou…
Jak jsem psal, největší problém je správně specifikovat zadání. Řešení už pak bude snadné.
-
Ze zadání vyplývá, že "plaintextové reference" na uživatele a témata chce nahradit HTML okazy.
@john and @johnathan went to see @sarah in their #hometown to look at her new #home.
@john --> <a href="/user/john">@john</a>
#hometown --> <a href="/topic/hometown">#hometown</a>
...
Je jasné, že chce nahrazovat jen "kompletní tokeny".
-
Ze zadání vyplývá, že "plaintextové reference" na uživatele a témata chce nahradit HTML okazy.
@john and @johnathan went to see @sarah in their #hometown to look at her new #home.
@john --> <a href="/user/john">@john</a>
#hometown --> <a href="/topic/hometown">#hometown</a>
...
Je jasné, že chce nahrazovat jen "kompletní tokeny".
Ne, to ze zadání nevyplývá. Dokonce je zadání zavádějící.
Z navrženého řešení vyplynulo, že tokeny mohou obsahovat pouze malé a velké znaky anglické abecedy a číslice, a že se mají nahrazvat jen „celá slova“ neb ojak píšete vy „kompletní tokeny“. To v zadání nikde není a podstatně to zjednodušuje řešení. V zadání je naopak uvedeno: „Dalej potrebujem zarucit ze ked sa mi prekryvaju tokeny(john -> johnathan) tak sa vyrazy najdu a nahradia spravne.“ Což je ale zavádějící, protože při tom upraveném zadání (nahrazují se jen celá slova) tahle situace nikdy nemůže nastat.
Zkrátka tazatel nejprve napsal dotaz, a teprve pak začal přemýšlet nad tím, co vlastně chce.
Jinak řešení toho upraveného zadání je triviální. Šlo by to napsat i jako oneliner, ale lepší je napsat si na to funkci.
const input = "@john and @johnathan went to see @sarah in their #hometown to look at her new #home."
const handles = ["john", "johnathan", "sarah"].map(item => item.toLowerCase())
const topics = ["home", "hometown"].map(item => item.toLowerCase())
const replaceTokens = (input, symbol, tokens, replace) => {
const re = new RegExp(`${symbol}([a-zA-Z0-9]+)\b`, 'g')
return input.replaceAll(re, (patch, g1) => tokens.includes(g1.toLowerCase()) ? replace(g1) : g1)
}
let output = replaceTokens(input, '@', handles, (handle) => `<a href="/user/${handle}">@${handle}</a>`)
output = replaceTokens(output, '#', topics, (topic) => `<a href="/topic/${topic}">#${topic}</a>`)
console.log(output)
-
Tak ide to aj bez zbytocnych cyklov alebo callbacku pre kazdy vyskyt. To je v podstate skryte GOTO label. Regexpy vedia aj OR.
const
handles = ["john", "johnathan", "sarah"],
topics = ["home", "hometown"],
tmpString = "@john and @Johnathan went to see @sarah in their #hometown to look at her new #home.";
function rplacer(text){
return tmpString.replace(
new RegExp('@('+handles.join('|')+')\\b','gmi'),`<a href="/user/$1"@>$1</a>`
).replace(
new RegExp('#('+topics.join('|')+')\\b','gmi'),`<a href="/topics/$1">#$1</a>`
);
}
console.log(rplacer(tmpString))
-
pripadne mozeme aj objektovo...
var Rplacer = function(opts) {
var priv = {}, pub = {};
priv.opts = opts.map(function(obj){
obj.re = new RegExp(obj.prefix+'('+obj.tokens.join('|')+')\\b','gmi')
return obj;
});
pub.replace = function(input){
priv.opts.forEach(function(x){
input = input.replace(x.re,x.replace);
});
return input;
}
return pub;
};
var r = Rplacer([
{
prefix: '@',
tokens:['john','johnathan','sarah'],
replace:`<a href="/user/$1">@$1</a>`
},{
prefix: '#',
tokens:["home", "hometown"],
replace:`<a href="/topics/$1">#$1</a>`
}
]);
console.log(r.replace('@john and @johnathan went to see @Sarah in their #hometown to look at her new #home.'));
-
Ne, to ze zadání nevyplývá. Dokonce je zadání zavádějící.
Bez urazky, pokud nebyl prvni prispevek editovan (autorem), pak by ses mel zamyslet, nad tim co tu pises.
-
Tak ide to aj bez zbytocnych cyklov alebo callbacku pre kazdy vyskyt. To je v podstate skryte GOTO label. Regexpy vedia aj OR.
const
handles = ["john", "johnathan", "sarah"],
topics = ["home", "hometown"],
tmpString = "@john and @Johnathan went to see @sarah in their #hometown to look at her new #home.";
function rplacer(text){
return tmpString.replace(
new RegExp('@('+handles.join('|')+')\\b','gmi'),`<a href="/user/$1"@>$1</a>`
).replace(
new RegExp('#('+topics.join('|')+')\\b','gmi'),`<a href="/topics/$1">#$1</a>`
);
}
console.log(rplacer(tmpString))
Takhle můžeš jen doufat, že nikoho nenapadne zadat handles = ["john.doe"], ono to jde ještě dál, hodnoty v handles a topics se dají přímo využít pro XSS. Takovýhle způsob psaní kódu je dost nebezpečný.
-
Tak ide to aj bez zbytocnych cyklov alebo callbacku pre kazdy vyskyt. To je v podstate skryte GOTO label. Regexpy vedia aj OR.
const
handles = ["john", "johnathan", "sarah"],
topics = ["home", "hometown"],
tmpString = "@john and @Johnathan went to see @sarah in their #hometown to look at her new #home.";
function rplacer(text){
return tmpString.replace(
new RegExp('@('+handles.join('|')+')\\b','gmi'),`<a href="/user/$1"@>$1</a>`
).replace(
new RegExp('#('+topics.join('|')+')\\b','gmi'),`<a href="/topics/$1">#$1</a>`
);
}
console.log(rplacer(tmpString))
Takhle můžeš jen doufat, že nikoho nenapadne zadat handles = ["john.doe"], ono to jde ještě dál, hodnoty v handles a topics se dají přímo využít pro XSS. Takovýhle způsob psaní kódu je dost nebezpečný.
To by musel mat moznost zmenit ten script. Ak bude mat moznost zmenit ten script tak nebude vymyslat blbiny ako zneuzit handles a topic, ze ano....
-
Bez urazky, pokud nebyl prvni prispevek editovan (autorem), pak by ses mel zamyslet, nad tim co tu pises.
Takhle můžeš jen doufat, že nikoho nenapadne zadat handles = ["john.doe"], ono to jde ještě dál, hodnoty v handles a topics se dají přímo využít pro XSS. Takovýhle způsob psaní kódu je dost nebezpečný.
_Tomáši_, děkuji za odpověď dirka12345, že úvodní zadání je opravdu špatně napsané. Tazatel totiž později svým kódem naznačil, že oba dva druhy tokenů mohou obsahovat pouze malá a velká písmena anglické abecedy a arabské číslice. Tečka tedy mezi povolené znaky nepatří, ani menšítko, ampersand nebo uvozovky, takže pro XSS to využít nejde, i kdyby měl uživatel možnost ty hodnoty upravovat.
-
Tak ide to aj bez zbytocnych cyklov alebo callbacku pre kazdy vyskyt. To je v podstate skryte GOTO label. Regexpy vedia aj OR.
Ano, kód se dá vždycky znepřehlednit. Ten callback je tam schválně, protože pak si můžete s nahrazováním dělat, co chcete, můžete každý token nahrazovat něčím jiným. Skryté GOTO vůbec ničemu nevadí – problém s klasickým GOTO je to, že znepřehledňuje kód. Co je efektivnější, jestli ten složený regexp nebo vyhledávání tokenů v poli, by se muselo změřit – ale vzhledem k tomu, že je to celé v JavaScriptu, mi to připadá jako velmi předčasná optimalizace. O možnosti použít OR v regulárních výrazech samozřejmě vím. Ale jednak v tom mlhavém zadání není řečeno, jak s emá pracovat s něčím, co vypadá jako token ale neví v seznamu tokenů – moje řešení umožňuje takové případy ignorovat (jak je to napsané), ale zároveň umožňuje na to nějak zareagovat, třeba ten token alespoň zalogovat. A druhá věc je to, na co upozornil _Tomáš_ – že cpát něco, co pravděpodobně může uživatel ovlivnit, bez escapování do regulárního výrazu, je dost nebezpečné. Ano, teď jsou jako tokeny povolea jen písmena a číslice, ale pokud by se někdo později rozhodl to změnit, nemusí mu dojít, že má upravit i tohle vytváření regulárních výrazů.
-
Tak samorejme, kazdu funkcionalitu je mozne napisat mnoho roznymi sposobmi. Ja ale nerad miesam roznu funkcionalitu do konkretnej casti programu. Ta funkcia zodpoveda za specificke nahradenie textu. Funkcionalita na validaciu tych tokenov je samozrejme za urcitych okolnosti ziaduca, ale nesuvysi priamo z fukcionalitou nahradzovania. Rovnako ako escapovanie riadiacich znakov v tom tokene. Nebudeme predsa pisat spagetak.
Co sa tyka efektivnosti, tak ten regexp byva prakticky v kazdom interpretri zkompilovany z ineho jazyka (zvedsa C). Ak si musi z toho kompilovaneho kodu zbytocne odskakovat do interpretru, tak efektivita klesa.
-
Rovnako ako escapovanie riadiacich znakov v tom tokene.
Gratuluju, to je vůbec ten nejlepší způsob, jak vyrobit *injection chybu v aplikaci. Prostě si na všechn místech, kde by se to dalo ošetřit, říct „hm, to už je určitě ošetřené někde jinde“.
Nebudeme predsa pisat spagetak.
To s tím nijak nesouvisí.
Co sa tyka efektivnosti, tak ten regexp byva prakticky v kazdom interpretri zkompilovany z ineho jazyka (zvedsa C). Ak si musi z toho kompilovaneho kodu zbytocne odskakovat do interpretru, tak efektivita klesa.
To je klasická předčasná optimalizace. Navíc jenom hádáte, jak by asi tak mohl interpret JavaScriptu fungovat. Přitom dnes budete těžko hledat nějaký interpret, který by optimalizoval víc, než interprety JavaScriptu v prohlížeči (zejména V8). Možná by se to dalo srovnávat tak s JVM, pokud ji budeme považovat za interpret.
-
_Tomáši_, děkuji za odpověď dirka12345, že úvodní zadání je opravdu špatně napsané.
Pardon? Je toto puvodni zadani https://forum.root.cz/index.php?topic=25683.msg364308#msg364308 ? Co s tim ma spolecnyho naky reseni. Jeden z nas si sedi na kabelu. Jasne tam rika co cim chce nahradit. Nicmene hadat se nebudu, cau.
-
_Tomáši_, děkuji za odpověď dirka12345, že úvodní zadání je opravdu špatně napsané.
Pardon? Je toto puvodni zadani https://forum.root.cz/index.php?topic=25683.msg364308#msg364308 ? Co s tim ma spolecnyho naky reseni. Jeden z nas si sedi na kabelu. Jasne tam rika co cim chce nahradit. Nicmene hadat se nebudu, cau.
Kdybyste si přečetl celou diskusi, dozvěděl byste se, že toto bylo původní zadání, které bylo kritizováno za nepřesnost – a v průběhu diskuse z tazatele postupně vylezlo, že chce vlastně něco úplně jiného. A v diskusi jsou správná řešení různých zadání, tak, jak z tazatele postupně lezlo, co vlastně chce.
-
Gratuluju, to je vůbec ten nejlepší způsob, jak vyrobit *injection chybu v aplikaci. Prostě si na všechn místech, kde by se to dalo ošetřit, říct „hm, to už je určitě ošetřené někde jinde“.
To ze to neviete, neznamena ze to nejde.
var Rplacer = function(opts) {
var priv = {}, pub = {};
// vykona sa raz, sem patri pripadna kontrola vstupu
priv.opts = opts.map(function(obj){
obj.re = new RegExp(obj.prefix+'('+obj.tokens.join('|')+')\\b','gmi')
return obj;
});
// samotne nahradzovanie, volat sa moze do aleluja
pub.replace = function(input){
priv.opts.forEach(function(x){
input = input.replace(x.re,x.replace);
});
return input;
}
return pub;
};
var r = Rplacer([
{
prefix: '@',
tokens:['john','johnathan','sarah'],
replace:`<a href="/user/$1">@$1</a>`
},{
prefix: '#',
tokens:["home", "hometown"],
replace:`<a href="/topics/$1">#$1</a>`
}
]);
console.log(r.replace('@john and @johnathan went to see @Sarah in their #hometown to look at her new #home.'));
To s tím nijak nesouvisí.
Suvisi.
To je klasická předčasná optimalizace. Navíc jenom hádáte, jak by asi tak mohl interpret JavaScriptu fungovat. Přitom dnes budete těžko hledat nějaký interpret, který by optimalizoval víc, než interprety JavaScriptu v prohlížeči (zejména V8). Možná by se to dalo srovnávat tak s JVM, pokud ji budeme považovat za interpret.
Predcasnej optimalizacie sa dopustate vy. Ak by ste mal aspom tusenie ako funguje V8 (ale aj spidermonkey) tak by ste vedel ze v prvom rade sa medzikod interpretuje, a az ked je k dispozicii dostatok informacii o kode tak pride na rad jit. Ale aj tamsu 2 moznosti, bud rychlejsi bez optimalizacii alebo pomalsi optimalizovany. To je ale logicke, ak je cena za jit + beh vacsia ako cena za interpret tak nema zmysel kompilovat. Kdezto vykonny kod toho regexp je VZDY skompilovany a interpret/jit ho len zavola s pattern ako parametrom.
-
To ze to neviete, neznamena ze to nejde.
Já jsem ale nepsal, že to nejde. Já jsem kritizoval to, že jste to odbyl „to se vyřeší někde jinde“. Má to být v kódu hned u kódu, který to používá. Třeba aspoň tak, jak jste to napsal v příkladu vy.
To s tím nijak nesouvisí.
Suvisi.
To, že to neumíte napsat dobře, neznamená, že to dobře napsat nejde. A nakonec jste sám napsal příklad, který je špagetový jenom trochu, přitom je to tam ošetřené. Dalo by se to samozřejmě napsat tak, aby tam špaget bylo ještě méně. Dalo by se to napsat i objektově (a bez špaget).
Predcasnej optimalizacie sa dopustate vy.
V čem?
Ak by ste mal aspom tusenie ako funguje V8 (ale aj spidermonkey)
Nosíte dříví do lesa. Mám pro vás takovou pomůcku, až se zase budete pokoušet někoho poučovat. Když napíšete, jak něco funguje, zkuste to následně porovnat s textem toho, koho poučujete. Když zjistíte, že to, co napsal, není v žádném rozporu s vaším poučováním, nemáte žádný důvod myslet si, že dotyčný neví to, o čem ho poučujete. Takže to poučování zase můžete smazat.
Případně, pokud je tenhle postup na vás moc složitý, mám pro vás i jednodušší variantu: Pokud napíšete text, ve kterém někoho poučujete, zase ten text smažte.
Kdezto vykonny kod toho regexp je VZDY skompilovany
No a co? Vy používáte regexp, já používám regexp, takže ten váš výkonný zkompilovaný kód (o kterém se mimochodem jenom domníváte, že je zkompilovaný) používáme oba dva. Pokud si myslíte, že váš kód je lepší, zkuste hledat místa, ve kterých se ten kód liší, ne ta, která jsou stejná.
Mimochodem, změřit dobu běhu kódu není zas tak těžké. Čísla z měření by mne přesvěčila, vaše dojmy mne nepřesvědčí.
-
Já jsem ale nepsal, že to nejde. Já jsem kritizoval to, že jste to odbyl „to se vyřeší někde jinde“. Má to být v kódu hned u kódu, který to používá. Třeba aspoň tak, jak jste to napsal v příkladu vy.
Tak ako som to napisal ja, to nemusi byt nutne spolu, moze to byt v predkovi z inej kniznice. Tak nejak predpokladam ze programujete v jave. Tak by ste to vediet mal.
To, že to neumíte napsat dobře, neznamená, že to dobře napsat nejde. A nakonec jste sám napsal příklad, který je špagetový jenom trochu, přitom je to tam ošetřené. Dalo by se to samozřejmě napsat tak, aby tam špaget bylo ještě méně. Dalo by se to napsat i objektově (a bez špaget).
Magicke funkcie ktore zahrnaju viacero funkcnosti v jednom, je skolsky priklad spagetaku.
V čem?
V tom ze sa automaticky spusti jit kompilator.
Nosíte dříví do lesa. Mám pro vás takovou pomůcku, až se zase budete pokoušet někoho poučovat. Když napíšete, jak něco funguje, zkuste to následně porovnat s textem toho, koho poučujete. Když zjistíte, že to, co napsal, není v žádném rozporu s vaším poučováním, nemáte žádný důvod myslet si, že dotyčný neví to, o čem ho poučujete. Takže to poučování zase můžete smazat.
Případně, pokud je tenhle postup na vás moc složitý, mám pro vás i jednodušší variantu: Pokud napíšete text, ve kterém někoho poučujete, zase ten text smažte.
Vas text:
To je klasická předčasná optimalizace. Navíc jenom hádáte, jak by asi tak mohl interpret JavaScriptu fungovat. Přitom dnes budete těžko hledat nějaký interpret, který by optimalizoval víc, než interprety JavaScriptu v prohlížeči (zejména V8). Možná by se to dalo srovnávat tak s JVM, pokud ji budeme považovat za interpret.
Moj text:
Predcasnej optimalizacie sa dopustate vy. Ak by ste mal aspom tusenie ako funguje V8 (ale aj spidermonkey) tak by ste vedel ze v prvom rade sa medzikod interpretuje, a az ked je k dispozicii dostatok informacii o kode tak pride na rad jit. Ale aj tamsu 2 moznosti, bud rychlejsi bez optimalizacii alebo pomalsi optimalizovany. To je ale logicke, ak je cena za jit + beh vacsia ako cena za interpret tak nema zmysel kompilovat. Kdezto vykonny kod toho regexp je VZDY skompilovany a interpret/jit ho len zavola s pattern ako parametrom.
Ja nepoucujem ale pisem svoj nazor, na zaklade svojich skusenosti. Ak nemate dispozicie viest dialog, ale vydupavat si to ze ako jediny mate pravdu, tak pravidelna navsteva diskuzneho fora musi byt pre vas velkym utrpenim. Sucitim s vami.
No a co? Vy používáte regexp, já používám regexp, takže ten váš výkonný zkompilovaný kód (o kterém se mimochodem jenom domníváte, že je zkompilovaný) používáme oba dva. Pokud si myslíte, že váš kód je lepší, zkuste hledat místa, ve kterých se ten kód liší, ne ta, která jsou stejná.
Mimochodem, změřit dobu běhu kódu není zas tak těžké. Čísla z měření by mne přesvěčila, vaše dojmy mne nepřesvědčí.
Ak ja curam po vetre a vy proti vetru, tak to neznamena ze to robite lepsie nez ja. I ked ja curam, vy curate. K poznaniu ze curanie proti vetru nie je dobry napad, nemusim nutne skusit vas sposob.
-
Tak ako som to napisal ja, to nemusi byt nutne spolu, moze to byt v predkovi z inej kniznice.
Objektové programování je jeden ze způsobů, jak udržovat pohromadě kód, který k sobě patří (předci třídy).
Magicke funkcie ktore zahrnaju viacero funkcnosti v jednom, je skolsky priklad spagetaku.
Ano. Ale nebylo by nijak pracné váš kód zbavit špaget – což jste viděl sám a umístil jste komentáře tam, kde by mohla být funkce.
V tom ze sa automaticky spusti jit kompilator.
Mýlíte se. To, jestli se spustí či nespustí JIT kompilátor nedokáže autor JavaScriptového kódu přímočaře ovlivnit. Pokud nevíte, co znamená termín „předčasná optimalizace“ – znamená to, že autor kódu napíše kód jinak, než by ho psal normálně, v domnění, že takový kód bude efektivnější.
Ak by ste mal aspom tusenie ako funguje V8
Ja nepoucujem ale pisem svoj nazor, na zaklade svojich skusenosti. Ak nemate dispozicie viest dialog, ale vydupavat si to ze ako jediny mate pravdu, tak pravidelna navsteva diskuzneho fora musi byt pre vas velkym utrpenim. Sucitim s vami.
Aha, takže ta první citace není poučování.
Já normálně diskutuju, nevydupávám si, že jako jediný mám pravdu. Ale nevím, proč bych nemohl upozornit na to, když někdo napíše něco špatně. Pokud se vás takové upozornění dotýká, je to váš problém, ne můj.
Ak ja curam po vetre a vy proti vetru, tak to neznamena ze to robite lepsie nez ja. I ked ja curam, vy curate. K poznaniu ze curanie proti vetru nie je dobry napad, nemusim nutne skusit vas sposob.
Zkoušet to samozřejmě nemusíte. Problém je, když vítr fouká opačným směrem, než si myslíte.
-
Objektové programování je jeden ze způsobů, jak udržovat pohromadě kód, který k sobě patří (předci třídy).
Ale rozhodie nie tak ze to vsetko strcite do jednej funkcie/metody.
Ano. Ale nebylo by nijak pracné váš kód zbavit špaget – což jste viděl sám a umístil jste komentáře tam, kde by mohla být funkce.
Kometarmi zbavit kod spagiet... To by chcelo zapis na wikicitaty :D
Mýlíte se. To, jestli se spustí či nespustí JIT kompilátor nedokáže autor JavaScriptového kódu přímočaře ovlivnit. Pokud nevíte, co znamená termín „předčasná optimalizace“ – znamená to, že autor kódu napíše kód jinak, než by ho psal normálně, v domnění, že takový kód bude efektivnější.
Tak co myslite, co bude efektivnejsie. Funkcia F napisana v C(alebo v ruste v pripade spidermonkey) ktoru zavolam s predpipravenym parametrom, alebo kod ktory sa mozno interpretuje, mozno prelozi a potom zavola a napokon bude volat funkciu F? Fakt si to potrebujete zmerat?
Aha, takže ta první citace není poučování.
Já normálně diskutuju, nevydupávám si, že jako jediný mám pravdu. Ale nevím, proč bych nemohl upozornit na to, když někdo napíše něco špatně. Pokud se vás takové upozornění dotýká, je to váš problém, ne můj.
Je rozdiel medzi poucovanim, a domienkou. Preto som zacal s "ak". Naproti tomu vy ani nepoucujete, vy rovno kadrujete "Navíc jenom hádáte, jak by asi tak mohl interpret JavaScriptu fungovat."
Ad normalna diskusia: Nemam ten dojem ze by to tu bolo preplnene ludmi s ktorymi najdete spolocnu rec. Skor na opak. Ste si naozaj isty ze problem nie je vo vas ale v masach?
Zkoušet to samozřejmě nemusíte. Problém je, když vítr fouká opačným směrem, než si myslíte.
Uvazujte trochu. Ak curam po vetre, tak som v suchu. To ze som v suchu je dostatocne overenie, bez toho aby som musel skusat vas sposob.
-
Ale rozhodie nie tak ze to vsetko strcite do jednej funkcie/metody.
Někdo snad tvridl opak?
Kometarmi zbavit kod spagiet... To by chcelo zapis na wikicitaty :D
To jste ovšem teď napsal vy. Já jsem nic takového nenapsal.
Tak co myslite, co bude efektivnejsie. Funkcia F napisana v C(alebo v ruste v pripade spidermonkey) ktoru zavolam s predpipravenym parametrom, alebo kod ktory sa mozno interpretuje, mozno prelozi a potom zavola a napokon bude volat funkciu F? Fakt si to potrebujete zmerat?
Za prvé, prohlédněte si znovu a lépe kód, který jsem napsal. Porovnáváte volání funkce F s jendím parametrem s voláním funkce F s jiným parametrem.
Za druhé, nikde není řečeno, že interpretovaný kód musí volat funkci F. Výhoda JIT je, že optimalizuje kód na míru aktuálnímu běhu programu. Takže ten kód může být mnohem efektivnější, než obecná optimalizace vznikající v okamžiku jednorázového překladu aplikaci. Efektivnější může být například i tím, že nebude volat obecnou funkci F, ale zavolá mnohem rychlejší specializovanější funkci F'. Tohle byste ovšem měl vědět, když se tu prezentujete jako odborník na JIT kompilaci.
Je rozdiel medzi poucovanim, a domienkou. Preto som zacal s "ak". Naproti tomu vy ani nepoucujete, vy rovno kadrujete "Navíc jenom hádáte, jak by asi tak mohl interpret JavaScriptu fungovat."
Aha, no dobře, bude všechny své domněnky pro vás uvozovat „ak“.
Ad normalna diskusia: Nemam ten dojem ze by to tu bolo preplnene ludmi s ktorymi najdete spolocnu rec. Skor na opak. Ste si naozaj isty ze problem nie je vo vas ale v masach?
O věcech, o kterých si myslím, že masy vědí stejně nebo lépe než já, nepíšu. O takových věcech si čtu, případně se ptám. Ak vy píšete o věcech, o kterých toho masy vědí víc, než vy, leccos by to vysvětlovalo. Akorát bych řekl, že v takovém případě by bylo lepší, kdybyste nic nepsal.
To ze som v suchu
No jo, jenže vy nejste v suchu. Vy jenom tvrdíte, že se rozhodně nebudete dívat na své kalhoty, protože fouká severní vítr.
-
Někdo snad tvridl opak?
Myslim ze kazdy si dokaze dohladat co ste tvrdil.
To jste ovšem teď napsal vy. Já jsem nic takového nenapsal.
Aj to si kazdy vie dohladat.
Za prvé, prohlédněte si znovu a lépe kód, který jsem napsal. Porovnáváte volání funkce F s jendím parametrem s voláním funkce F s jiným parametrem.
Za druhé, nikde není řečeno, že interpretovaný kód musí volat funkci F. Výhoda JIT je, že optimalizuje kód na míru aktuálnímu běhu programu. Takže ten kód může být mnohem efektivnější, než obecná optimalizace vznikající v okamžiku jednorázového překladu aplikaci. Efektivnější může být například i tím, že nebude volat obecnou funkci F, ale zavolá mnohem rychlejší specializovanější funkci F'. Tohle byste ovšem měl vědět, když se tu prezentujete jako odborník na JIT kompilaci.
Njn, vy tam tu funkciu F volate opakovane. Naviac ju mate v podmienke ktora na vysledku tej funkcie zavisi. Takze vam ju ziadny optimalizator nevyhodi. Mal by ste si niekedy skusit pracu architekta. Naucil by ste sa zhodnotit narocnost algoritmu este pred tym nez by ho niekto implementoval...
Aha, no dobře, bude všechny své domněnky pro vás uvozovat „ak“.
Staci ak to budete formulovat ako domienku.
O věcech, o kterých si myslím, že masy vědí stejně nebo lépe než já, nepíšu. O takových věcech si čtu, případně se ptám. Ak vy píšete o věcech, o kterých toho masy vědí víc, než vy, leccos by to vysvětlovalo. Akorát bych řekl, že v takovém případě by bylo lepší, kdybyste nic nepsal.
No a ze toho denne minimalne na roote popisete akurat dost a z toho ste spravidla vecsinu s niekym v konflikte. Mat tolko casu ako vy (nemam, praca, rodina a konicky) tak tie mudra masam predlozim v clankoch na damu temu. Bolo by to efektivnejsie ako niekomu musiet neustale dookola dokazovat ze mate vacsieho...
No jo, jenže vy nejste v suchu. Vy jenom tvrdíte, že se rozhodně nebudete dívat na své kalhoty, protože fouká severní vítr.
Na to ze mam suche nohavice, zistim pomocou receptorov v pokozke noh, nepotrebujem zatazovat zrakovy nerv. K tomu ma nedonuti ani trolenie, ktore moze fungovat iba tak na masy na ksichtoknihe...
-
Myslim ze kazdy si dokaze dohladat co ste tvrdil.
Aj to si kazdy vie dohladat.
Ano, k vaší smůle.
Njn, vy tam tu funkciu F volate opakovane.
Ak jste zapomněl, co je ta vaše funkce F, připomenu vám to – je to vyhledávání regulárního výrazu v řetězci. Což volám dvakrát, jednou pro každý druh tokenu. Stejně jako vy.
z toho ste spravidla vecsinu s niekym v konflikte
Zatímco vy v diskusích jenom přitákáváte, že. Protože to je smysl diskuse – někdo něco napíše, a a na dalších pěti stránkách všichni přitakávají, že s tím souhlasí.
-
Tak jsem napsal primitivní test porovnávající mou funkci (funcA), vaši funkci (funcB) a ještě upravenou mou funkci s tím, že se místo hledání v neseřazeném poli používá hashovací tabulka (funcC). Testoval jsem to v deno, ale pak jsem výsledek uložil jako Codepen, abyste si to mohl spustit i v prohlížeči. Výsledky z prohlížeče i deno jsou plus mínus autobus stejné, ale přesnější výsledky nejsou myslím potřeba. Výsledná čísla tu snad raději ani zveřejňovat nebudu, abyste to nebral jako urážku.
https://codepen.io/filipjirsak/pen/RwLqNJg
Prosím vás, na ty vaše kalhoty se přeci jen podívejte. Podívejte se na ně i zezadu. Nebude to hezký pohled.
-
S dovolením jsem vynechal stranu 2 a stranu 3, takže jsem přišel o baladu o kalhotech a větrech ze severu. (Možná si to přečtu až budu potřebovat upustit páru)
Ale tohle má být nějaká vysokoškolská úloha, kdy máš vymyslet algoritmus, nebo jen potřebuješ poradit existující funkci z knihovny? (Klíčem implementace je nezamotat se v opakujících subvýrazech, jak v vyhledávacím kroku, tak v nahrazovacím kroku-v případě že by se nahrazovalo imperativně v cyklu. Radši bych slovo krok uplně vynechal)
MŮJ ROZBOR
Já bych přispěl druhým možným algoritmem - v první fázi provedu jen vyhledání. Vzniká problém, že může vzniknout víc řešení vyhledání výrazů. Nabízí se hledání podle nejdelšího, ale pak stále tu zůstane problém, co třeba s patterny "bene" a "nebe" pro slovo "benebe, be". Tohle pořadí musí si určit programátor sám. Jako bonus tam můžeme přihodit pattern "be"
Fáze nahrazovací musí proběhnout "transakčně". Třeba nejdřív určením ochranného znaku třeba #, potom nahrazením # třeba za #0. Pak nahrazením patternů za #1, #2.... (#N - N=přirozená čísla=bez nuly) Pak nahrazením #N za nahrazené varianty a nakonec vrácením #0 za #...
Ale třeba zadání může být i takové, aby se nahrazovalo donekonečna... V tom případě právě transakčnost je nežádoucí a může z toho vzniknout turingův stroj, pokud se nepletu. Radši to típnu
A jinak bych poradil funkci preg_replace_callback a její ekvivalenty. Možná by ani nebyla potřeba nahrazovací část řešena být callbackově.
-
SO odpoved ak by niekto potreboval do buducna:
Než jsem vám stihl odpovědět, že máte neúplné zadání, tak jste si našel odpověď. Zrada, proč vaše zadání nebude fungovat je nejasná definice chování replace
Máš a nemáš pravdu. Pravděpodobně mu vznikne jiný než zamýšlený výsledek (smutně mu tam bude koukat "town"). A zároveň se to zacyklí. (ale to spolu nesouvisí, řekl bych že zjednodušeně zacyklení závisí na vztahu náhrada-pattern a neočekávané nahrazování shodou substringů patternů)
-
A především (možná v rámci zjednodušení a pochopení) by bylo vhodné normalizovat hledané výrazy...
To znamená místo oddělených proměnných handles a topics mít
jedno pole [ *handles , *topics] neboli [john,johnathan, town, hometown] a k nim příslušně pole náhrad [href-h-john, href-h-jonathan, href-t-town, href-t-hometown]
Až pochopí tazatel, kde je problém, může pokračovat dál a pustit se do složitějších věcí, jako callbackové nahrazování
Mimochodem: není náhodou správně Jonathan (ostatně třeba i správně je errorneous). Tady je to snad jen pro příklad.
-
Tak jsem napsal primitivní test porovnávající mou funkci (funcA), vaši funkci (funcB) a ještě upravenou mou funkci s tím, že se místo hledání v neseřazeném poli používá hashovací tabulka (funcC). Testoval jsem to v deno, ale pak jsem výsledek uložil jako Codepen, abyste si to mohl spustit i v prohlížeči. Výsledky z prohlížeče i deno jsou plus mínus autobus stejné, ale přesnější výsledky nejsou myslím potřeba. Výsledná čísla tu snad raději ani zveřejňovat nebudu, abyste to nebral jako urážku.
https://codepen.io/filipjirsak/pen/RwLqNJg
Prosím vás, na ty vaše kalhoty se přeci jen podívejte. Podívejte se na ně i zezadu. Nebude to hezký pohled.
No neke, tak si to skuste opravit funcA a funcC aby ich vystup nevratil to iste ako je input. FuncB nieco skutocne nahradzuje a je daleko pomalsia koli tomu ze robi to co sa pozadovalo - nahradzuje najdene retazce. Mozno to na 2 pokus date ;)
-
Tak jsem napsal primitivní test porovnávající mou funkci (funcA), vaši funkci (funcB) a ještě upravenou mou funkci s tím, že se místo hledání v neseřazeném poli používá hashovací tabulka (funcC). Testoval jsem to v deno, ale pak jsem výsledek uložil jako Codepen, abyste si to mohl spustit i v prohlížeči. Výsledky z prohlížeče i deno jsou plus mínus autobus stejné, ale přesnější výsledky nejsou myslím potřeba. Výsledná čísla tu snad raději ani zveřejňovat nebudu, abyste to nebral jako urážku.
https://codepen.io/filipjirsak/pen/RwLqNJg
Prosím vás, na ty vaše kalhoty se přeci jen podívejte. Podívejte se na ně i zezadu. Nebude to hezký pohled.
Ked tak https://jsfiddle.net/DeathWalker/ps5my816/
-
A jinak bych poradil funkci preg_replace_callback a její ekvivalenty. Možná by ani nebyla potřeba nahrazovací část řešena být callbackově.
On to chce v javascripte, nie v php.
V php je to este jednoduchsie (predpoklada sa validne pole $tokens):
<?php
$input = '@john and @johnathan went to see @sarah in their #hometown to look at her new #home.';
$tokens =[
[ 'selector' => '@',
'hrefPrefix' => '/user',
'items' => [
'john',
'johnathan',
'sarah'
],
],
[ 'selector' => '#',
'hrefPrefix' => '/topics',
'items' => [
'home',
'hometown',
],
],
];
$patterns = $tokens;
$replacements = [];
array_walk($patterns, function(&$item,$key) use (&$replacements){
$replacements[$key] = "<a href=\"{$item['hrefPrefix']}/$2\">$1</a>";
$temp = array_map(function($item){
return preg_quote($item);
},$item['items']);
$temp = join('|',$temp);
$item = "~({$item['selector']}({$temp}))\\b~mi";
});
$output = preg_replace($patterns,$replacements,$input);
echo "$output\n"
Z toho dostaneme:
<a href="/user/john">@john</a> and <a href="/user/johnathan">@johnathan</a> went to see <a href="/user/sarah">@sarah</a> in their <a href="/topics/hometown">#hometown</a> to look at her new <a href="/topics/home">#home</a>.
-
https://codepen.io/filipjirsak/pen/RwLqNJg
No neke, tak si to skuste opravit funcA a funcC aby ich vystup nevratil to iste ako je input. FuncB nieco skutocne nahradzuje a je daleko pomalsia koli tomu ze robi to co sa pozadovalo - nahradzuje najdene retazce. Mozno to na 2 pokus date ;)
Dobře, speciálně pro vás jsem na konec přidal ještě porovnání výstupů. Ak byste tomu kódu nerozuměl, tak jsem tam přidal i výpis vstupu a výstupu, můžete si to porovnat očima.
Tak co, už můžeme zveřejnit výsledky, že ten váš kód je cca 3× pomalejší?
Každopádně vám děkuji za názorný příklad toho, proč je předčasná optimalizace špatně. Pustil jste se do optimalizace něčeho, o čem jste vůbec nevěděl, zda je to pomalé. A při optimalizaci jste ve skutečnosti vyrobil třikrát pomalejší kód. Asi jste se (mylně) domníval, že regulární výrazy jsou jakási magie, jejíž složitost můžete zanedbat. Ak byste tušil, jak regulární výrazy fungují, napadlo by vás, že jste tím vaším kódem pravděpodobně vyrobil tu vnitřní smyčku, kterou jste vytýkal mému kódu (a která v mém kódu není).
Zkuste si z toho zapamatovat alespoň to, že svislítko | v regulárních výrazech je vždy nebezpečné, pokud vám jde o výkon. A na vašem místě bych také přehodnotil přístup, že nemusíte měřit rychlost kódu, protože máte představu, co je asi jak rychlé. Evidentně jsou vaši představy o fungování kódu mylné.
-
https://codepen.io/filipjirsak/pen/RwLqNJg
No neke, tak si to skuste opravit funcA a funcC aby ich vystup nevratil to iste ako je input. FuncB nieco skutocne nahradzuje a je daleko pomalsia koli tomu ze robi to co sa pozadovalo - nahradzuje najdene retazce. Mozno to na 2 pokus date ;)
Dobře, speciálně pro vás jsem na konec přidal ještě porovnání výstupů. Ak byste tomu kódu nerozuměl, tak jsem tam přidal i výpis vstupu a výstupu, můžete si to porovnat očima.
Tak co, už můžeme zveřejnit výsledky, že ten váš kód je cca 3× pomalejší?
Každopádně vám děkuji za názorný příklad toho, proč je předčasná optimalizace špatně. Pustil jste se do optimalizace něčeho, o čem jste vůbec nevěděl, zda je to pomalé. A při optimalizaci jste ve skutečnosti vyrobil třikrát pomalejší kód. Asi jste se (mylně) domníval, že regulární výrazy jsou jakási magie, jejíž složitost můžete zanedbat. Ak byste tušil, jak regulární výrazy fungují, napadlo by vás, že jste tím vaším kódem pravděpodobně vyrobil tu vnitřní smyčku, kterou jste vytýkal mému kódu (a která v mém kódu není).
Zkuste si z toho zapamatovat alespoň to, že svislítko | v regulárních výrazech je vždy nebezpečné, pokud vám jde o výkon. A na vašem místě bych také přehodnotil přístup, že nemusíte měřit rychlost kódu, protože máte představu, co je asi jak rychlé. Evidentně jsou vaši představy o fungování kódu mylné.
A teraz by to chcelo zrovnat branky, bud by ste mal pouzit kod ktory ste sem postoval, alebo ja ten svoj optimalizujem. 3x pomalsie je to koli tomu joinu, ktory si logicky musi alokovat pamat. Naviac ked ten kod prebehne 1000000 krat tak jit s optimalizatorom bezpecne zafunguje. Preco by ale niekto ten isty text nahradzoval 1000000x dookola?
-
https://codepen.io/filipjirsak/pen/RwLqNJg
No neke, tak si to skuste opravit funcA a funcC aby ich vystup nevratil to iste ako je input. FuncB nieco skutocne nahradzuje a je daleko pomalsia koli tomu ze robi to co sa pozadovalo - nahradzuje najdene retazce. Mozno to na 2 pokus date ;)
Dobře, speciálně pro vás jsem na konec přidal ještě porovnání výstupů. Ak byste tomu kódu nerozuměl, tak jsem tam přidal i výpis vstupu a výstupu, můžete si to porovnat očima.
Tak co, už můžeme zveřejnit výsledky, že ten váš kód je cca 3× pomalejší?
Každopádně vám děkuji za názorný příklad toho, proč je předčasná optimalizace špatně. Pustil jste se do optimalizace něčeho, o čem jste vůbec nevěděl, zda je to pomalé. A při optimalizaci jste ve skutečnosti vyrobil třikrát pomalejší kód. Asi jste se (mylně) domníval, že regulární výrazy jsou jakási magie, jejíž složitost můžete zanedbat. Ak byste tušil, jak regulární výrazy fungují, napadlo by vás, že jste tím vaším kódem pravděpodobně vyrobil tu vnitřní smyčku, kterou jste vytýkal mému kódu (a která v mém kódu není).
Zkuste si z toho zapamatovat alespoň to, že svislítko | v regulárních výrazech je vždy nebezpečné, pokud vám jde o výkon. A na vašem místě bych také přehodnotil přístup, že nemusíte měřit rychlost kódu, protože máte představu, co je asi jak rychlé. Evidentně jsou vaši představy o fungování kódu mylné.
Njn, ako som si myslel.
Pre:
const reHandles = new RegExp('@(' + handles.join('|') + ')\\b', 'gmi');
const reTopics = new RegExp('#(' + topics.join('|') + ')\\b', 'gmi');
.
.
.
.
const funcB = (input, handles, topics) => {
return input.replace(reHandles, `<a href="/user/$1">@$1</a>`)
.replace(reTopics, `<a href="/topic/$1">#$1</a>`);
}
Je funcA vyrazne pomalsia. A funcB a funcC su porovnatelne. Ale to je len tym ze sa ten kod zopakuje milion krat a tym ste si zarucil ze sa to zkompiluje.
-
A teraz by to chcelo zrovnat branky, bud by ste mal pouzit kod ktory ste sem postoval, alebo ja ten svoj optimalizujem.
Vy jste tvrdil, že je pomalé volat pro každé nahrazení funkci. To je kód, který je v tom testu. Já jsem v mém původním návrhu měl feturu navíc, že bylo možné každý token nahrazovat jinou náhradou, takže se tam volala další funkce. Nic takového váš kód nedělá, takže jsem srovnal podmínky tak, aby oba kódy dělaly to samé.
Naviac ked ten kod prebehne 1000000 krat tak jit s optimalizatorom bezpecne zafunguje. Preco by ale niekto ten isty text nahradzoval 1000000x dookola?
To jsou zase jen vaše dohady. Které se neukázaly jako moc dobré. Ak byste někdy dělal výkonnostní testy aplikace, věděl byste, že se kód často volá opakovaně, aby se výkon vůbec dal nějak změřit. Proč by někdo ten stejný text nahrazoval 1 000 000 × dokola byste měl odpovědět vy, protože vy jste přišel s tím, že je potřeba to optimalizovat na čas. Pokud se ten text bude nahrazovat jenom jednou a trvá to po jednu milisekundu, proč to optimalizovat?
Ale že jste to vy, dal jsem tam přesnější čítač času, takže teď už to můžete pustit i jenom jednou. Akorát že zjistíte, že to už se pohybujeme v oblasti chyby měření a jediné, co se dá říct, je to, že výkon těch funkcí je zhruba stejný. Což je opět v rozporu s vaší tvrzením, že můj kód je neefektivní.
Njn, ako som si myslel.
Njn, jenže to už testujete něco jiného, protože jste kus vaší funkce vytrhl mimo test, takže neměříte dobu trvání celé vaší funkce. Pak je to opravdu optimalizace na velký počet nahrazování se stejnou sadou tokenů (což je zase váš nevyslovený předpoklad, že něco takového bude potřeba), tedy je to jiné zadání. Jinak v tomhle speciálním případu (o kterém ale původně nebyla řeč) je vaše funkce opravdu cca o 1/3 rychlejší. Láme se to teprve u dost vysokého počtu tokenů – u deseti tisíc tokenů už je výrazně efektivnější hledání tokenů v hashmapě než jejich procházení po jednom v regulárním výrazu.
Ale to je len tym ze sa ten kod zopakuje milion krat a tym ste si zarucil ze sa to zkompiluje.
To vaše vytváření regulárního výrazu se zaručeně nezkompiluje ani při milionu provedení?
-
A teraz by to chcelo zrovnat branky, bud by ste mal pouzit kod ktory ste sem postoval, alebo ja ten svoj optimalizujem.
Vy jste tvrdil, že je pomalé volat pro každé nahrazení funkci. To je kód, který je v tom testu. Já jsem v mém původním návrhu měl feturu navíc, že bylo možné každý token nahrazovat jinou náhradou, takže se tam volala další funkce. Nic takového váš kód nedělá, takže jsem srovnal podmínky tak, aby oba kódy dělaly to samé.
Njn, ako som si myslel.
Njn, jenže to už testujete něco jiného, protože jste kus vaší funkce vytrhl mimo test, takže neměříte dobu trvání celé vaší funkce. Pak je to opravdu optimalizace na velký počet nahrazování se stejnou sadou tokenů (což je zase váš nevyslovený předpoklad, že něco takového bude potřeba), tedy je to jiné zadání. Jinak v tomhle speciálním případu (o kterém ale původně nebyla řeč) je vaše funkce opravdu cca o 1/3 rychlejší. Láme se to teprve u dost vysokého počtu tokenů – u deseti tisíc tokenů už je výrazně efektivnější hledání tokenů v hashmapě než jejich procházení po jednom v regulárním výrazu.
Takze vy si svoj kodoptimalizujete ale pritom trvate aby ten moj ostal v povodnej podobe. Ste tak ferovy :D Nehrajte marias ani ine podobne hry, mohlo by to byt bolestive. :D
Naviac ked ten kod prebehne 1000000 krat tak jit s optimalizatorom bezpecne zafunguje. Preco by ale niekto ten isty text nahradzoval 1000000x dookola?
To jsou zase jen vaše dohady. Které se neukázaly jako moc dobré. Ak byste někdy dělal výkonnostní testy aplikace, věděl byste, že se kód často volá opakovaně, aby se výkon vůbec dal nějak změřit. Proč by někdo ten stejný text nahrazoval 1 000 000 × dokola byste měl odpovědět vy, protože vy jste přišel s tím, že je potřeba to optimalizovat na čas. Pokud se ten text bude nahrazovat jenom jednou a trvá to po jednu milisekundu, proč to optimalizovat?
Ale že jste to vy, dal jsem tam přesnější čítač času, takže teď už to můžete pustit i jenom jednou. Akorát že zjistíte, že to už se pohybujeme v oblasti chyby měření a jediné, co se dá říct, je to, že výkon těch funkcí je zhruba stejný. Což je opět v rozporu s vaší tvrzením, že můj kód je neefektivní.
Pozrite si ako JIT v javascripte funguje. Pri neopakovani kodu takmer vzdy pobezi interpret. JIT zafunguje az po niekolkych opakovaniach.
Ale to je len tym ze sa ten kod zopakuje milion krat a tym ste si zarucil ze sa to zkompiluje.
To vaše vytváření regulárního výrazu se zaručeně nezkompiluje ani při milionu provedení?
Mno, to RE engine je uz skompilovane, vsak. Rovnako sa skompiluje aj ten regular, ci uz pomocou re.compile alebo volanimtoho isteho s konstruktoru. Je skompilovane vzdy a nie len v urcitych pripadoch.
-
Takze vy si svoj kodoptimalizujete ale pritom trvate aby ten moj ostal v povodnej podobe. Ste tak ferovy :D Nehrajte marias ani ine podobne hry, mohlo by to byt bolestive. :D
Já jsem pouze kód upravil tak, aby obě dvě verze dělaly funkčně to samé. Ano, když chci porovnat dva přístupy k řešení téhož problému, připadá mi férové, když obě varianty řeší tentýž problém a ne když jedna varianta toho umí mnohem víc, co není k řešení problému potřeba.
Vy si svůj kód klidně optimalizujte, nikde jsem nepsal, že to dělat nesmíte. Akorát by to měla být optimalizace řešení problému a ne optimalizace pro konkrétní test. taky bych uměl „optimalizovat“ kód tak, že si rovnou uložím výstupní text k příslušnému testu do proměnné a nebudu volat žádnou funkci.
Pozrite si ako JIT v javascripte funguje.
Že máte po tom fiasku pořád odvahu někoho poučovat…
Mno, to RE engine je uz skompilovane, vsak. Rovnako sa skompiluje aj ten regular, ci uz pomocou re.compile alebo volanimtoho isteho s konstruktoru. Je skompilovane vzdy a nie len v urcitych pripadoch.
Ono není skompilovat jako skompilovat. Můžete kompilovat do nativního kódu, do optimalizovaného nativního kódu, do AST, do bajtkódu…