Index: src/foptions.pas
===================================================================
--- src/foptions.pas	(revision 8429)
+++ src/foptions.pas	(working copy)
@@ -211,7 +211,7 @@
           if TOptionsEditorView(Node2.Data).EditorClass.ClassName='TfrmOptionsLanguage' then
             result:=1
           else
-            result:=CompareStrings(Node1.Text,Node2.Text, gSortNatural, gSortCaseSensitivity)
+            result:=CompareStrings(Node1.Text, Node2.Text, gSortNatural, gSortSpecial, gSortCaseSensitivity)
       end;
   end;
 
Index: src/frames/foptionsdirectoryhotlist.pas
===================================================================
--- src/frames/foptionsdirectoryhotlist.pas	(revision 8430)
+++ src/frames/foptionsdirectoryhotlist.pas	(working copy)
@@ -1781,7 +1781,7 @@
 
 function CompareStringsFromTStringList(List: TStringList; Index1, Index2: integer): integer;
 begin
-  Result := CompareStrings(List.Strings[Index1], List.Strings[Index2], gSortNatural, gSortCaseSensitivity);
+  Result := CompareStrings(List.Strings[Index1], List.Strings[Index2], gSortNatural, gSortSpecial, gSortCaseSensitivity);
 end;
 
 { TfrmOptionsDirectoryHotlist.TryToGetCloserHotDir }
@@ -1875,7 +1875,7 @@
 
       if Result <> nil then
       begin
-        if CompareStrings(localDirToFindAPlaceFor, UTF8LowerCase(IncludeTrailingPathDelimiter(mbExpandFileName(tHotDir(Result.Data).HotDirPath))), gSortNatural, gSortCaseSensitivity) = -1 then TypeOfAddition := ACTION_INSERTHOTDIR;
+        if CompareStrings(localDirToFindAPlaceFor, UTF8LowerCase(IncludeTrailingPathDelimiter(mbExpandFileName(tHotDir(Result.Data).HotDirPath))), gSortNatural, gSortSpecial, gSortCaseSensitivity) = -1 then TypeOfAddition := ACTION_INSERTHOTDIR;
       end;
     finally
       MagickSortedList.Free;
@@ -2108,7 +2108,7 @@
 begin
   if (THotdir(Node1.Data).GroupNumber = THotDir(Node2.Data).GroupNumber) and (THotdir(Node1.Data).GroupNumber <> 0) then
   begin
-    Result := CompareStrings(THotdir(Node1.Data).HotDirName, THotDir(Node2.Data).HotDirName, gSortNatural, gSortCaseSensitivity);
+    Result := CompareStrings(THotdir(Node1.Data).HotDirName, THotDir(Node2.Data).HotDirName, gSortNatural, gSortSpecial, gSortCaseSensitivity);
   end
   else
   begin
Index: src/frames/foptionsfavoritetabs.pas
===================================================================
--- src/frames/foptionsfavoritetabs.pas	(revision 8429)
+++ src/frames/foptionsfavoritetabs.pas	(working copy)
@@ -262,7 +262,7 @@
 
 function CompareStringsFromTStringList(List: TStringList; Index1, Index2: integer): integer;
 begin
-  Result := CompareStrings(List.Strings[Index1], List.Strings[Index2], gSortNatural, gSortCaseSensitivity);
+  Result := CompareStrings(List.Strings[Index1], List.Strings[Index2], gSortNatural, gSortSpecial, gSortCaseSensitivity);
 end;
 
 { TfrmOptionsFavoriteTabs.btnRenameClick }
@@ -325,7 +325,7 @@
 begin
   if (TFavoriteTabs(Node1.Data).GroupNumber = TFavoriteTabs(Node2.Data).GroupNumber) and (TFavoriteTabs(Node1.Data).GroupNumber <> 0) then
   begin
-    Result := CompareStrings(TFavoriteTabs(Node1.Data).FavoriteTabsName, TFavoriteTabs(Node2.Data).FavoriteTabsName, gSortNatural, gSortCaseSensitivity);
+    Result := CompareStrings(TFavoriteTabs(Node1.Data).FavoriteTabsName, TFavoriteTabs(Node2.Data).FavoriteTabsName, gSortNatural, gSortSpecial, gSortCaseSensitivity);
   end
   else
   begin
Index: src/frames/foptionsfilesviews.pas
===================================================================
--- src/frames/foptionsfilesviews.pas	(revision 8429)
+++ src/frames/foptionsfilesviews.pas	(working copy)
@@ -144,6 +144,8 @@
     cbSortMethod.ItemIndex:= 0
   else
     cbSortMethod.ItemIndex:= 1;
+  if gSortSpecial then
+    cbSortMethod.ItemIndex := cbSortMethod.ItemIndex + 2;
   case gSortFolderMode of
     sfmSortNameShowFirst:      cbSortFolderMode.ItemIndex := 0;
     sfmSortLikeFileShowFirst:  cbSortFolderMode.ItemIndex := 1;
@@ -198,7 +200,8 @@
     1: gSortCaseSensitivity := cstLocale;
     2: gSortCaseSensitivity := cstCharValue;
   end;
-  gSortNatural := (cbSortMethod.ItemIndex = 1);
+  gSortNatural := (cbSortMethod.ItemIndex in [1,3]);
+  gSortSpecial := (cbSortMethod.ItemIndex in [2,3]);
   case cbSortFolderMode.ItemIndex of
     0: gSortFolderMode := sfmSortNameShowFirst;
     1: gSortFolderMode := sfmSortLikeFileShowFirst;
Index: src/udcutils.pas
===================================================================
--- src/udcutils.pas	(revision 8429)
+++ src/udcutils.pas	(working copy)
@@ -184,14 +184,13 @@
 }
 procedure SplitCmdLine(sCmdLine : String; var sCmd, sParams : String);
 {$ENDIF}
-function CompareStrings(const s1, s2: String; Natural: Boolean; CaseSensitivity: TCaseSensitivity): PtrInt;
+function CompareStrings(const s1, s2: String; Natural: Boolean; Special: Boolean; CaseSensitivity: TCaseSensitivity): PtrInt;
 
 procedure InsertFirstItem(sLine: String; comboBox: TCustomComboBox);
 {en
-   Compares two strings taking into account the numbers.
-   Strings must have tailing zeros (#0).
+   Compares two strings taking into account the numbers or special chararcters.
 }
-function StrFloatCmpW(str1, str2: PWideChar; CaseSensitivity: TCaseSensitivity): PtrInt;
+function StrChunkCmp(const str1, str2: String; Natural: Boolean; Special: Boolean; CaseSensitivity: TCaseSensitivity): PtrInt;
 
 function EstimateRemainingTime(StartValue, CurrentValue, EndValue: Int64;
                                StartTime: TDateTime; CurrentTime: TDateTime;
@@ -804,10 +803,10 @@
 end;
 {$ENDIF}
 
-function CompareStrings(const s1, s2: String; Natural: Boolean; CaseSensitivity: TCaseSensitivity): PtrInt; inline;
+function CompareStrings(const s1, s2: String; Natural: Boolean; Special: Boolean; CaseSensitivity: TCaseSensitivity): PtrInt; inline;
 begin
-  if Natural then
-    Result:= StrFloatCmpW(PWideChar(UTF8Decode(s1)), PWideChar(UTF8Decode(s2)), CaseSensitivity)
+  if Natural or Special then
+    Result:= StrChunkCmp(s1, s2, Natural, Special, CaseSensitivity)
   else
     begin
       case CaseSensitivity of
@@ -863,161 +862,159 @@
    Result := ord(pstr1[counter]) - ord(pstr2[counter]);
  end;
 
-function StrFloatCmpW(str1, str2: PWideChar; CaseSensitivity: TCaseSensitivity): PtrInt;
+function StrChunkCmp(const str1, str2: String; Natural: Boolean; Special: Boolean; CaseSensitivity: TCaseSensitivity): PtrInt;
+
+type
+  TCategory = (cNone, cNumber, cSpecial, cString);
+
+  TChunk = record
+    FullStr: String;
+    Str: String;
+    Category: TCategory;
+    PosStart: Integer;
+    PosEnd: Integer;
+  end;
+
 var
-  is_digit1, is_digit2: boolean;
-  string_result: ptrint = 0;
-  number_result: ptrint = 0;
-  number1_size: ptrint = 0;
-  number2_size: ptrint = 0;
-  str_cmp: function(const s1, s2: WideString): PtrInt;
+  Chunk1, Chunk2: TChunk;
 
-  function is_digit(c: widechar): boolean; inline;
+  function Categorize(c: Char): TCategory; inline;
   begin
-    result:= (c in ['0'..'9']);
+    if Natural and (c in ['0'..'9']) then
+      Result := cNumber
+    else if Special and (c in [' '..'/', ':'..'@', '['..'`', '{'..'~']) then
+      Result := cSpecial
+    else
+      Result := cString;
   end;
 
-  function is_point(c: widechar): boolean; inline;
+  procedure NextChunkInit(var Chunk: TChunk); inline;
   begin
-    result:= (c in [',', '.']);
+    Chunk.PosStart := Chunk.PosEnd;
+    if Chunk.PosStart > Length(Chunk.FullStr) then
+      Chunk.Category := cNone
+    else
+      Chunk.Category := Categorize(Chunk.FullStr[Chunk.PosStart]);
   end;
 
-begin
-  // Set up compare function
-  case CaseSensitivity of
-    cstNotSensitive: str_cmp:= @WideCompareText;
-    cstLocale:       str_cmp:= @WideCompareStr;
-    cstCharValue:    str_cmp:= @WideStrComp;
-    else
-      raise Exception.Create('Invalid CaseSensitivity parameter');
+  procedure FindChunk(var Chunk: TChunk); inline;
+  begin
+    Chunk.PosEnd := Chunk.PosStart;
+    repeat
+      inc(Chunk.PosEnd);
+    until (Chunk.PosEnd > Length(Chunk.FullStr)) or
+          (Categorize(Chunk.FullStr[Chunk.PosEnd]) <> Chunk.Category);
   end;
 
-  while (true) do
+  procedure FindSameCategoryChunks; inline;
   begin
-    // compare string part
-    while (true) do
-    begin
-      if str1^ = #0 then
-      begin
-        if str2^ <> #0 then
-          exit(-1)
-        else
-          exit(0);
-      end;
+    Chunk1.PosEnd := Chunk1.PosStart;
+    Chunk2.PosEnd := Chunk2.PosStart;
+    repeat
+      inc(Chunk1.PosEnd);
+      inc(Chunk2.PosEnd);
+    until (Chunk1.PosEnd > Length(Chunk1.FullStr)) or
+          (Chunk2.PosEnd > Length(Chunk2.FullStr)) or
+          (Categorize(Chunk1.FullStr[Chunk1.PosEnd]) <> Chunk1.Category) or
+          (Categorize(Chunk2.FullStr[Chunk2.PosEnd]) <> Chunk2.Category);
+  end;
 
-      if str2^ = #0 then
-      begin
-        if str1^ <> #0 then
-          exit(+1)
-        else
-          exit(0);
-      end;
+  procedure PrepareChunk(var Chunk: TChunk); inline;
+  begin
+    Chunk.Str := Copy(Chunk.FullStr, Chunk.PosStart, Chunk.PosEnd - Chunk.PosStart);
+  end;
 
-      is_digit1 := is_digit(str1^);
-      is_digit2 := is_digit(str2^);
+  procedure PrepareNumberChunk(var Chunk: TChunk); inline;
+  begin
+    while (Chunk.PosStart <= Length(Chunk.FullStr)) and
+          (Chunk.FullStr[Chunk.PosStart] = '0') do
+      inc(Chunk.PosStart);
+    PrepareChunk(Chunk);
+  end;
 
-      if (is_digit1 and is_digit2) then break;
+begin
+  Chunk1.FullStr := str1;
+  Chunk2.FullStr := str2;
+  Chunk1.PosEnd := 1;
+  Chunk2.PosEnd := 1;
 
-      string_result:= str_cmp(str1^, str2^);
+  NextChunkInit(Chunk1);
+  NextChunkInit(Chunk2);
 
-      if (string_result <> 0) then exit(string_result);
+  if (Chunk1.Category = cSpecial) and (Chunk2.Category <> cSpecial) then
+    Exit(-1);
+  if (Chunk2.Category = cSpecial) and (Chunk1.Category <> cSpecial) then
+    Exit(1);
 
-      inc(str1);
-      inc(str2);
-    end;
+  if Chunk1.Category = cSpecial then
+    FindSameCategoryChunks
+  else
+  begin
+    FindChunk(Chunk1);
+    FindChunk(Chunk2);
+  end;
 
-    // skip leading zeroes for number
-    while (str1^ = '0') do
-      inc(str1);
-    while (str2^ = '0') do
-      inc(str2);
+  if (Chunk1.Category = cNumber) xor (Chunk2.Category = cNumber) then // one of them is number
+    Chunk1.Category := cString; // compare as strings to put numbers in a natural position
 
-    // compare number before decimal point
-    while (true) do
-    begin
-      is_digit1 := is_digit(str1^);
-      is_digit2 := is_digit(str2^);
+  while True do
+  begin
 
-      if (not is_digit1 and not is_digit2) then
-        break;
-
-      if ((number_result = 0) and is_digit1 and is_digit2) then
-      begin
-        if (str1^ > str2^) then
-          number_result := +1
-        else if (str1^ < str2^) then
-          number_result := -1
-        else
-          number_result := 0;
-      end;
-
-      if (is_digit1) then
-      begin
-        inc(str1);
-        inc(number1_size);
-      end;
-
-      if (is_digit2) then
-      begin
-        inc(str2);
-        inc(number2_size);
-      end;
-    end;
-
-    if (number1_size <> number2_size) then
-      exit(number1_size - number2_size);
-
-    if (number_result <> 0) then
-      exit(number_result);
-
-    // if there is a decimal point, compare number after one
-    if (is_point(str1^) or is_point(str2^)) then
-    begin
-      if (is_point(str1^)) then
-        inc(str1);
-
-      if (is_point(str2^)) then
-        inc(str2);
-
-      while (true) do
-      begin
-        is_digit1 := is_digit(str1^);
-        is_digit2 := is_digit(str2^);
-
-        if (not is_digit1 and not is_digit2) then
-          break;
-
-        if (is_digit1 and not is_digit2) then
+    case Chunk1.Category of
+      cString:
         begin
-          while (str1^ = '0') do
-            inc(str1);
-
-          if (is_digit(str1^)) then
-            exit(+1)
-          else
-            break;
+          PrepareChunk(Chunk1);
+          PrepareChunk(Chunk2);
+          case CaseSensitivity of
+            cstNotSensitive: Result := WideCompareText(UTF8Decode(Chunk1.Str), UTF8Decode(Chunk2.Str));
+            cstLocale:       Result := WideCompareStr(UTF8Decode(Chunk1.Str), UTF8Decode(Chunk2.Str));
+            cstCharValue:    Result := WideStrComp(UTF8Decode(Chunk1.Str), UTF8Decode(Chunk2.Str));
+            else
+              raise Exception.Create('Invalid CaseSensitivity parameter');
+          end;
+          if Result <> 0 then
+            Exit;
         end;
-
-        if (is_digit2 and not is_digit1) then
+      cNumber:
         begin
-          while (str2^ = '0') do
-            inc(str2);
-
-          if (is_digit(str2^)) then
-            exit(-1)
-          else
-            break;
+          PrepareNumberChunk(Chunk1);
+          PrepareNumberChunk(Chunk2);
+          Result := Length(Chunk1.Str) - Length(Chunk2.Str);
+          if Result <> 0 then
+            Exit;
+          Result := CompareStr(Chunk1.Str, Chunk2.Str);
+          if Result <> 0 then
+            Exit;
         end;
+      cSpecial:
+        begin
+          PrepareChunk(Chunk1);
+          PrepareChunk(Chunk2);
+          Result := CompareStr(Chunk1.Str, Chunk2.Str);
+          if Result <> 0 then
+            Exit;
+        end;
+      cNone:
+        Exit(WideStrComp(UTF8Decode(str1), UTF8Decode(str2)));
+    end;
 
-        if (str1^ > str2^) then
-          exit(+1)
-        else if (str1^ < str2^) then
-          exit(-1);
+    NextChunkInit(Chunk1);
+    NextChunkInit(Chunk2);
 
-        inc(str1);
-        inc(str2);
-      end;
+    if Chunk1.Category <> Chunk2.Category then
+      if Chunk1.Category < Chunk2.Category then
+        Exit(-1)
+      else
+        Exit(1);
+
+    if Chunk1.Category = cSpecial then
+      FindSameCategoryChunks
+    else
+    begin
+      FindChunk(Chunk1);
+      FindChunk(Chunk2);
     end;
+
   end;
 end;
 
Index: src/ufilesorting.pas
===================================================================
--- src/ufilesorting.pas	(revision 8429)
+++ src/ufilesorting.pas	(working copy)
@@ -453,12 +453,12 @@
   else if (gSortFolderMode <> sfmSortNameShowFirst) then
     Result := 0
   else
-    Result := CompareStrings(item1.Name, item2.Name, gSortNatural, gSortCaseSensitivity);
+    Result := CompareStrings(item1.Name, item2.Name, gSortNatural, gSortSpecial, gSortCaseSensitivity);
 end;
 
 function ICompareByName(item1, item2: TFile; bSortNegative: Boolean):Integer;
 begin
-  Result := CompareStrings(item1.Name, item2.Name, gSortNatural, gSortCaseSensitivity);
+  Result := CompareStrings(item1.Name, item2.Name, gSortNatural, gSortSpecial, gSortCaseSensitivity);
 
   if bSortNegative then
     Result := -Result;
@@ -475,7 +475,7 @@
   end
   else
   begin
-    Result := CompareStrings(item1.NameNoExt, item2.NameNoExt, gSortNatural, gSortCaseSensitivity);
+    Result := CompareStrings(item1.NameNoExt, item2.NameNoExt, gSortNatural, gSortSpecial, gSortCaseSensitivity);
 
     if bSortNegative then
       Result := -Result;
@@ -484,7 +484,7 @@
 
 function ICompareByExt(item1, item2: TFile; bSortNegative: Boolean):Integer;
 begin
-  Result := CompareStrings(item1.Extension, item2.Extension, gSortNatural, gSortCaseSensitivity);
+  Result := CompareStrings(item1.Extension, item2.Extension, gSortNatural, gSortSpecial, gSortCaseSensitivity);
 
   if bSortNegative then
     Result := -Result;
@@ -552,7 +552,7 @@
 function ICompareByVariant(Value1, Value2: Variant; bSortNegative: Boolean):Integer;
 begin
   if VarIsType(Value1, varString) then
-    Result := CompareStrings(Value1, Value2, gSortNatural, gSortCaseSensitivity)
+    Result := CompareStrings(Value1, Value2, gSortNatural, gSortSpecial, gSortCaseSensitivity)
   else if Value1 = Value2 then
     Exit(0)
   else
Index: src/uglobs.pas
===================================================================
--- src/uglobs.pas	(revision 8429)
+++ src/uglobs.pas	(working copy)
@@ -264,6 +264,7 @@
   gRunTermParams: String;
   gSortCaseSensitivity: TCaseSensitivity;
   gSortNatural: Boolean;
+  gSortSpecial: Boolean;
   gSortFolderMode: TSortFolderMode;
   gNewFilesPosition: TNewFilesPosition;
   gUpdatedFilesPosition: TUpdatedFilesPosition;
@@ -1378,6 +1379,7 @@
   gLynxLike := True;
   gSortCaseSensitivity := cstNotSensitive;
   gSortNatural := False;
+  gSortSpecial := False;
   gSortFolderMode := sfmSortNameShowFirst;
   gNewFilesPosition := nfpSortedPosition;
   gUpdatedFilesPosition := ufpNoChange;
@@ -2382,6 +2384,7 @@
       begin
         gSortCaseSensitivity := TCaseSensitivity(GetValue(SubNode, 'CaseSensitivity', Integer(gSortCaseSensitivity)));
         gSortNatural := GetValue(SubNode, 'NaturalSorting', gSortNatural);
+        gSortSpecial := GetValue(SubNode, 'SpecialSorting', gSortSpecial);
         gSortFolderMode:= TSortFolderMode(GetValue(SubNode, 'SortFolderMode', Integer(gSortFolderMode)));
         gNewFilesPosition := TNewFilesPosition(GetValue(SubNode, 'NewFilesPosition', Integer(gNewFilesPosition)));
         gUpdatedFilesPosition := TUpdatedFilesPosition(GetValue(SubNode, 'UpdatedFilesPosition', Integer(gUpdatedFilesPosition)));
@@ -2976,6 +2979,7 @@
     SubNode := FindNode(Node, 'Sorting', True);
     SetValue(SubNode, 'CaseSensitivity', Integer(gSortCaseSensitivity));
     SetValue(SubNode, 'NaturalSorting', gSortNatural);
+    SetValue(SubNode, 'SpecialSorting', gSortSpecial);
     SetValue(SubNode, 'SortFolderMode', Integer(gSortFolderMode));
     SetValue(SubNode, 'NewFilesPosition', Integer(gNewFilesPosition));
     SetValue(SubNode, 'UpdatedFilesPosition', Integer(gUpdatedFilesPosition));
Index: src/ulng.pas
===================================================================
--- src/ulng.pas	(revision 8429)
+++ src/ulng.pas	(working copy)
@@ -749,7 +749,7 @@
   rsOptPluginSortOnlyWhenByExtension = 'Sorting WCX plugins is only possible when showing plugins by extension';
   rsPluginFilenameStyleList = 'With complete absolute path;Path relative to %COMMANDER_PATH%;Relative to the following';  
   //-------------------------------
-  rsOptSortMethod = 'Alphabetical, considering accents;Natural sorting: alphabetical and numbers';
+  rsOptSortMethod = 'Alphabetical, considering accents;Natural sorting: alphabetical and numbers;Alphabetical with special characters sort;Natural with special characters sort';
   rsOptSortCaseSens = 'not case sensitive;according to locale settings (aAbBcC);first upper then lower case (ABCabc)';
   rsOptSortFolderMode = 'sort by name and show first;sort like files and show first;sort like files';
   rsOptNewFilesPosition = 'at the top of the file list;after directories (if directories are sorted before files);at sorted position;at the bottom of the file list';
