Chciałbym opracować uniwersalny algorytm pobierania nazwy pliku z konsoli, czyli działający prawidłowo w Windows, MacOS i Linux (dowolna wersja i dowolna dystrybucja).
Założenie: Jest program pracujący w konsoli, w którym należy podać nazwę pliku. W momencie, jak program czeka na nazwę, użytkownik bierze ikonę pliku i upuszcza na konsolę, wpisuje się ścieżka i nazwa, po czym naciska Enter. Sama konsola interpretuje tę czynność jako wpisanie całej nazwy z klawiatury. Wobec tego, zbieramy naciśnięcia wszystkich klawiszy od chwili rozpoczęcia oczekiwania na plik, do naciśnięcia Enter. Otrzymaną nazwę zapisujemy jako napis (string).
Wszystko pięknie i ładnie, ale w praktyce, w Windows 10 i Ubuntu Linux dopisywane są dodatkowe znaki, które uniemożliwiają wykorzystanie tak podanej nazwy pliku, jak jest, trzeba ją odpowiednio przygotować.
Ja zauważyłem takie prawidłowości:
-
W Windows, jeżeli nazwa pliku lub któryś folder po drodze zawiera spację, to dopisuje się podwójny cudzysłów. Przypadek z cudzysłowem w nazwie nie jest możliwy, gdyż Windows nie pozwala na podwójny cudzysłów w nazwie. Jeżeli nie ma spacji, to nic się nie dopisuje.
-
W Ubuntu Linux, jeżeli nazwa zawiera spacje lub pojedynczy cudzysłów, nazwa jest obejmowana w pojedynczy cudzysłów, ale też na końcu dopisywana jest spacja. Ponadto, jeżeli w nazwie występuje pojedynczy cudzysłów, to każde wystąpienie
'
jest zamieniane na'\''
.
Jak jest w przypadku MacOS X? Jak jest w przypadku innych dystrybucji Linuxa?
Chodzi o to, żebym zrobił taki algorytm, który z tekstu wpisanego do konsoli poprzez przeciągnięcie ikony zrobił poprawną nazwę pliku ze ścieżką. Czy powyższe założenia i algorytm jest kompletny, czy coś jeszcze muszę uwzględnić, bo np. w MacOS jest jeszcze inaczej, a ja nie mam możliwości sprawdzić? Sam algorytm byłby jeden dla każdego OS.
Póki co, sam wymyśliłem taką funkcję przygotowującą nazwę pliku w C#, choć w tym przypadku język programowania nie ma większego znaczenia, chodzi o sam algorytm (nie wykluczone, że kiedyś będę chciał to samo zrobić w C++ lub w Java, przerobić na inny język to żaden problem).
public static string PrepareFileName(string NewFile_)
{
// Lista bialych znakow
List<char> Whitespaces = new List<char>();
Whitespaces.Add((char)0x20);
Whitespaces.Add((char)0xA0);
Whitespaces.Add((char)0x0D);
Whitespaces.Add((char)0x0A);
Whitespaces.Add((char)0x09);
// Obcinanie bialych znakow z poczatku
while ((NewFile_.Length > 0) && (Whitespaces.Contains(NewFile_[0])))
{
NewFile_ = NewFile_.Substring(1);
}
// Obcinanie bialych znakow z konca
while ((NewFile_.Length > 0) && (Whitespaces.Contains(NewFile_[NewFile_.Length - 1])))
{
NewFile_ = NewFile_.Substring(0, NewFile_.Length - 1);
}
if (NewFile_.Length >= 2)
{
// Nazwa pliku w podwojnym cudzyslowie - nalezy obciac cudzyslow, nic wiecej
if ((NewFile_[0] == '\"') && (NewFile_[NewFile_.Length - 1] == '\"'))
{
NewFile_ = NewFile_.Substring(1, NewFile_.Length - 2);
return NewFile_;
}
// Nazwa w pojedynczym cudzyslowie, nalezy obciac cudzyslow,
// ale oprocz tego zamienic "escape characters" na odpowiednie znaki
if ((NewFile_[0] == '\'') && (NewFile_[NewFile_.Length - 1] == '\''))
{
// Obcinanie cudzyslowu
NewFile_ = NewFile_.Substring(1, NewFile_.Length - 2);
// Interpretowanie "escape characters" i zamiana na odpowiednie znaki
string NewFile_0 = "";
bool InsideESC = false;
for (int i = 0; i < NewFile_.Length; i++)
{
if (NewFile_[i] == '\'')
{
InsideESC = !InsideESC;
}
else
{
if (InsideESC && (NewFile_[i] == '\\'))
{
i++;
switch (NewFile_[i])
{
case '\'':
case '\"':
case '\\':
NewFile_0 = NewFile_0 + NewFile_[i];
break;
}
}
else
{
NewFile_0 = NewFile_0 + NewFile_[i];
}
}
}
return NewFile_0;
}
}
return NewFile_;
}
Drugie pytanie: W Windows 10 i 11, jak konsola uruchomiona jest jako administrator, to przeciąganie pliku na konsolę nie działa. Jak to umożliwić?