#1 Recepta na – Multiple file extension
Niniejszy post rozpoczyna serię pt. „Recepta na”. Każdy post będzie dotyczył, jakiegoś małego problemu programistycznego i przykładowego rozwiązania. Takie małe, pomocne snippety.
Problem: Pobrać nazwę pliku bez jego rozszerzenia
.Net framework udostępnia metodę, która pozwala to jak najbardziej wykonać:
Path.GetExtension("sample.txt"); //-> ".txt" Path.GetFileNameWithoutExtension("sample.txt"); //-> "sample"
Niestety nie wspiera ona wielu rozszerzeń w nazwie, np. sample.tar.gz
Path.GetExtension("sample.tar.gz"); //-> ".gz" Path.GetFileNameWithoutExtension("sample.tar.gz"); //-> "sample.tar"
Jak spojrzymy w jej implementację zobaczymy, że poszukuję od końca przekazanej nazwy pierwszego wystąpienia kropki ’.’ i na tej podstawie zwraca substring od tego miejsca do końca. Dodatkowo wykonuje kilku walidacji. Link do implementacji
#1 Recepta
static string GetExtension(string filename) { return filename.Substring(filename.IndexOf('.'), filename.Length - filename.IndexOf('.')); }
Tak mogłaby wyglądać najprostsza implementacja, bez żadnych dodatkowych walidacji itp.
Ale przeczy to zasadzie a może intuicji że rozszerzenia poszukujemy od końca. Zbyt proste by mogło się sprawdzić.
#2 Recepta
Wykorzystać istniejąca metodę Path.GetExtension ale w taki sposób by wspierała wiele rozszerzeń. Zostaniemy przy „systemowej” implementacji co będzie dodatkowym atutem. Możemy to osiągnąć poprzez rekurencyjne wołanie w/w metody lub wykonanie tego w pętli. Rekurencja była zbyt prosta 😋 więc dziś przedstawię pętlę i to nie byle jaką – mianowicie do…while.
Rezultat końcowy:
static string GetFileNameWithoutExtension(string filename) { int maxCounter = 20, loopIndex = 0; string nameOnly, currentName = filename; Stack<string> extensions = new Stack<string>(); do { nameOnly = currentName; currentName = Path.GetFileNameWithoutExtension(nameOnly); extensions.Push(Path.GetExtension(nameOnly)); loopIndex++; } while (nameOnly != currentName && loopIndex <= maxCounter); return nameOnly; }
Wejściowa nazwa pliku jest „czyszczona” z rozszerzenia do momentu aż wywołanie metody Path.GetExtension zwraca tą samą nazwę. Wtedy wiemy, że metoda już nic więcej nie ma do roboty.
Zawarłem tutaj jeszcze kilka rzeczy:
- maxCounter – dodatkowe zabezpieczenie pętli aby uniknąć tzw. nieskończonej pętli
- Stack<string> extensions – stos na który odkładane są rozszerzenia.