Diskuze: Doplnění URL
V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.

Tvůrce

Zobrazeno 43 zpráv z 43.
//= Settings::TRACKING_CODE_B ?> //= Settings::TRACKING_CODE ?>
V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.
Co si představuješ pod pojmem "částečné URL"? Pokud jen relativní URL, tak kvůli tomu snad žádnou knihovnu nepotřebuješ.
Samozřejmě, že myslím relativní URL - když to chceš odborně, tak dobrá - chci převést relativní URL na absolutní URL...
Tak vysvětlení pro tebe - potřebuji k tomu použít jiný framework - a ve WPF projektu mi to bude dělat problémy - ani by to snad nešlo. Takže jsem založil další projekt - a knihovna se podle mě k tomuto účelu hodí. V ní jsem vyřešil problém se statickými daty - a stačí ji jen dostat do toho WPF projektu... Takže ji potřebuji...
Tak tomu rozumím ještě méně. Nikdy jsem netušil, že by někdo mohl potřebovat na "částečné URL" nějaký framework. Nestačilo by zavolat nějakou standardní funkci?
Jenom stále nevím, co si představuješ pod pojmem "částečné URL". Znám jen absolutní a relativní. Znám i všechny komponenty URL, ale fakt netuším, co je to "částečné URL". Vlastně všechna URL jsou částečná. Téměř nikdo nepoužívá kompletní URL.
Napsal jsem to tam odborně, co víc chceš... Co si představuješ pod pojmem standartní funkce? Jenom potřebuji použít v projektu plný framework, ne klientský. Jak píši, nejsou kompatibilní, ...
Co víc chci? Aby ti na ten tvůj dotaz konečně někdo odpověděl.
Nepsal jsem o žádné standartní, ale o standardní funkci. To znamená funkci, která je součástí programovacího jazyka, ve kterém píšeš svou aplikaci, případně nějaké jeho knihovny.
Pak to tvé podmínky splňuje - jen potřebuji jiný framework - který je součástí .NET...
Problém se mi zatím nepodařilo efektivně vyřešit. Aktuální podoba:
private string[] prefixes = { "https://", "http://", "https://www.", "http://www." };
...
public static bool UrlExists(string url)
{
try
{
WebRequest.Create(new Uri(url)).GetResponse();
return true;
}
catch
{
return false;
}
}
public string GetAbsoluteURL(string path)
{
this.Path = path;
return GetAbsoluteURL();
}
public string GetAbsoluteURL()
{
if (UrlExists(Path))
return Path;
else
{
foreach (string prefix in prefixes)
if (UrlExists(prefix + Path))
return prefix + Path;
}
return null;
}
Což sice funguje, ale třeba facebook.com to nenajde. Čily opravdu by se nedalo postupovat tak, jako prohlížeče postupují? Děkuji.
Pokud to má jít po webech, tak asi do podoby http://www.... můžeš doplňovat vždycky. Z http na https se přesměrovává až podle odpovědi serveru.
____________________________________________________
Ten tvůj "web pinger" je slušná čuňárna - jestli uživatel chce na
"http://www.seznam.cz" a napíše "seznam.cz", dohrabeš se ke správné url
po pěti requestech?! Víš, že někdy může request trvat třeba i pár
vteřin?
Nehledě teda na spojování stringů plusem, navíc úplně stupidně dvakrát
po sobě. Divím se, že někdo jako ty, kdo dělal parser a kompiler na
několik objektově orientovaných jazyků pro několik OS, klidně dělá
instaci konstaního pole stringů pro každou instanci třídy. Tok kódu
zásadně neřídíme pomocí try-catch! Od odborníka tvého formátu bych
čekal víc, chlapče...
Uh, ke kodu se radsi vyjadrovat nebudu, uz to udelal mtecl.
Ja bych to resil asi tak, ze bych zjistoval, zda slovo ma alespon 4 znaky
(nejkratsi adresa muze byt ve tvaru "a.cz") a obsahuje nejakou tecku, ktera neni
uplne na konci ani uplne na zacatku.
Pokud ano, zjistil bych, jestli za nejakou z tech "vnitrnich" tecek je string,
ktery odpovida nejake existujici domene prvniho radu. Pokud ano, tak bych to
slovo vzal a zacal ho zkoumat odpredu - jestli obsahuje protokol, tak uz bych ho
nechal byt, jestli chybi protokol, doplnil bych klasicky http (nejsem vestec,
abych hadal protokol za uzivatele, pokud ho nenapise) a pak zjistil, jestli tam
je domena tretiho radu a pripadne doplnil www...
O moc lip to asi uz resit nepujde...
Prohlížeče weby nevyhledávají. Pouze si z DNS zjistí IP adresu podle domény v URL.
Ta aktuální podoba vyhledávání je úplně špatně. Ten objekt nemá vracet URL, ale deskriptor otevřeného spojení.
A co tedy dělá
WebRequest.Create(new Uri(url)).GetResponse();
Vůbec nepoužíváš navatovou hodnotu. Přesně to bys měl vrátit returnem.
C# sice neumím, ale viděl bych to asi takto:
private string[] prefixes = { "", "https://", "http://", "https://www.", "http://www." };
...
public WebRequest OpenURL(string path) {
foreach (string prefix in prefixes) {
try {
return WebRequest.Create(new Uri(prefix + path)).GetResponse();
} catch (WebException e) {
}
}
throw new OpenURLException("Nepodařilo se otevřít " + path);
}
Pánové, takhle to fakt nejde... Co když někdo napíše "https://facebook.com"? Chrome si s tím poradí, ale vám vyletí výjimka "Nepodařilo se otevřít /…facebook.com".
Buď si Matesex bude muset přiznat, že tohle je nad jeho síly a uživatel prostě bude url zadávat přesně, nebo to chce něco si o formátu url přečíst, rozsekat na komponenty a pak doplnit do funkčního stavu.
Všiml sis těch prázdných uvozovek, které jsem připsal na začátek pole
prefixes
?
using System.Net;
using System;
namespace RunsWolf
{
public class URL
{
private string[] prefixes = { "", "http://", "http://www." };
public string Path { get; set; }
public URL ()
{
}
public URL (string path)
{
this.Path = path;
}
public WebResponse OpenURL(string path)
{
this.Path = path;
return OpenURL();
}
public WebResponse OpenURL()
{
foreach (string prefix in prefixes)
try
{
return WebRequest.Create(new Uri(prefix + Path)).GetResponse();
}
catch { }
throw new WebException("Nepodařilo se otevřít " + Path);
}
}
}
WebRequest může trvat i několik vteřin, takže pokud cíl prostě neexistuje, tak vyzkoušení všech tří předpon zabere tuším 15 sekund (pokud je defaultní timeout 5 sekund, nejsem si jistý).
Proto bych se snažil eliminovat počet pokusů na minimum a nejdříve si tu adresu zpracovat a zjistit, která část tam je a která není - nemá cenu před adresu lepit "http://", pokud už tak ta adresa začíná.
No 5 sekund to asi netrvá, jelikož nejdéle jsem čekal oněch 5 sekund - a to nemám nejrychlejší připojení... Takže těžko říci, zda rozebírat ten string nevyjde na stejno. Především - ty zadáváš absolutní URL? Právě proto to dělám - protože s ní nepočítám... Ale ještě si pořád hraji - kdo ví, na co narazím...
Nevšim. Ale - ty prázdné uvozovky jsou teda zrovna v tom případě co jsem napsal funkční, nicméně třeba pro vstup "https://seznam.cz" už ne. Prostě tímhle způsobem je to blbost.
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
foreach (var tst in GetTestEntries())
{
var repaired = RepairUrl(tst);
Console.WriteLine("{0} -> {1}", tst, repaired);
PrintResponse(repaired);
Console.WriteLine();
}
Console.ReadLine();
}
private static string RepairUrl(string uri)
{
if (string.IsNullOrWhiteSpace(uri))
throw new ArgumentException();
var protocol = "http";
uri = uri.Trim();
var protoInx = uri.IndexOf("://");
if (protoInx > -1)
{
protocol = uri.Substring(0, protoInx);
uri = uri.Substring(protoInx + 3);
}
var sb = new StringBuilder();
sb.Append(protocol);
sb.Append("://");
if (!uri.ToLower().TrimStart().StartsWith("www."))
sb.Append("www.");
sb.Append(uri);
return sb.ToString();
}
private static IEnumerable<string> GetTestEntries()
{
yield return "seznam.cz";
yield return "https://seznam.cz";
yield return "http://seznam.cz";
yield return "www.google.com";
yield return "http://google.com";
yield return "facebook.com";
yield return "google.cz#q=matesax";
}
private static void PrintResponse(string url)
{
var rq = WebRequest.Create(url);
using (var rdr = new StreamReader(rq.GetResponse().GetResponseStream()))
Console.WriteLine(rdr.ReadLine());
}
}
}
Ono to tak dlouho netrvá, protože WebRequest není mentál a většinou přijde na chybný formát URL ještě před zkoušením requestu.
Hlavně je blbost doplňovat to "www.".
Už tady bylo napsáno, že by bylo lepší URL parsovat a chybějící údaje doplnit, než takto pitomě rozšiřovat.
A tohle má být co?
catch { }
Za to se vyhazuje z práce.
Jinak jako jediný přínos tvého zápisu vidím jeho zbytečné prodloužení. Zřejmě proto, aby byl méně přehledný.
Co vlastně dělá metoda RepairUrl? Nedala by se využít třída Uri? Přinejhorším bych URL rozparsoval, doplnil údaje a složil. Takové harakiri na řetězcích by se s tím dělat nemělo.
Proč by se za to mělo vyhazovat z práce? I já občas použiju prázdný
catch.
Pokud je to něco, co nemá smysl logovat nebo nějak řešit a je to tam jen
kvůli tomu, aby ti kód nevyskočil ven z funkce v případě vyjímky, pak na
tom není nic špatného.
Vždycky bys měl vědět, kterou výjimku chceš zahodit. Neočekávanou výjimku bys měl vždy postoupit do dalších vrstev.
Zrovna u WebRequest.Create by mi v tomhle případě bylo celkem fuk, která z vyjímek byla vyhozena ( http://tinyurl.com/a9vmpms ), protoze realne tu muzu narazit vicemene jen na UriFormatException (maximalne pro jednu adresu z tisice jeste na SecurityException) a obe pro me znamenaji to same - tahle adresa je pro me nepouzitelna, zkousim dal.
Nevím na který můj post je to odpověď, ale přesně parsování a doplnění do kompletního stavu je to, co ten můj kód dělá.
Co se týče pužití Uri vs. harakiri, třída Uri, pokud něco takového
umí, uvnitř zřejmě musí dělat +- totéž. (Jen na rozdíl ode mě možná
kluci z MS uměj dobře regexy, no ). Samořejmě je vždy lepší použít něco nativního z .NETu, ale
to už se mi zas pro Matesaxe zkumat nechtělo. Každopádně jak je z toho
kódu vidět, repairUrl umí doplnit všechny běžné formáty nekompletní url
na formát akceptovaný WebRequest-em. Je to asi lepší, než původní
Matesaxův čuninec se zkoušením špatných variant a řízeím kódu
výjimkou.
Právě to jsem měl na mysli. Třídy a funkce, které jsou součástí jazyka, jsou obvykle tak dobře vytuněny, že by byl hřích toho nevyužít.
Vytuněny po stránce funkcí, po stránce rychlosti to občas docela
pokulhává
Zrovna třída Uri řeší většinu z toho, co se tady matesax snaží dělat opisem. Pokud někdo vybere nevhodnou metodu nebo ji použije špatně, tak to mívá dopad nejen na rychlost, ale jazyk za to nemůže.
Před pár lety jsem zkoušel rychlosti některých komponent a třeba Funce Sort u Listu (zkoušel jsem to asi na 100 000 Stringů) byla 10x pomalejší než má vlastní implementace.
Pro nějaké malé množství dat to samozřejmě je fuk, ale pro větší balíky dat už to je pomalé a je lepší použít implementaci vlastní.
Zřejmě proto, že tvá vlastní implementace zanedbávala NLS. Který algoritmus jsi použil?
U větších balíků dat bych se s řazením asi raději spolehl na
databázi. Bývá to v nich optimalizováno velmi dobře. Na objektový jazyk
žádná práce nezbude, takže pak už není co optimalizovat
Tak jsem to nasel a je to jen 4x rychlejsi, nevim uz, jestli jsem to
nezkousel predtim na jinem PC, ale mel jsem za to, ze to bylo skoro 10x
Ani nevim, jestli se NLS u bezneho porovnani stringu pouziva, ja to ignoruju,
radim jen podle pozice znaku v (rozsirene) ASCII tabulce.
Algoritmus mam nejakej vlastni, ani vlastne nevim, jakej, ale asi to bude nejaka
variace na BucketSort/RadixSort.
Psal jsem to v dobach, kdy jsem zacinal s C#, ted bych to zas napsal uplne
jinak
Radix sort je skvělý algoritmus, zejména na obrovské množství dat, ale pro obecné použití se moc nehodí. Je možné, že jsi s ním měl lepší výkon, než s obecným algoritmem.
Bucket sort vypadá také zajímavě.
V Javě/C# se NLS běžně používá a proto může být řazení
pomalejší. Ale že by až tak moc? Vyzkouším. Nic to však nemění na tom,
že na řazení velkého objemu dat mám raději DB
Už v konstruktoru Uri se přece dá použít druhý parametr, který doplní chybějící údaje.
No je tam leda tak doplnění relativní URL. Ale hlavně - ne všechny weby jedou na www... Čily stejně to budu muset nějak zjistit - jak? (Když ne pokusem načíst stránku...)
No nebude - již je...
Aktuálně dělám UI pro konzoli - boxy, panely,... Hodlám sem vše dát.
Zobrazeno 43 zpráv z 43.