Monday, March 4, 2019

C Sharp Get Server and Share a from UNC path

Here's a function that was surprisingly hard to find GetUNCHostShare from a directory path.

A UNC Share is defined as "\\host-name\share-name[\object-name]

ie \\server\share\dir1 

The string extension method returns "\\host-name\share-name.

Code Listing
using System;
     
public static class Program
{
 const string ShareExtUNCFullPrefix = @"\\?\UNC\";  
 const string ShareExtPrefix = @"\\?\";      
 const string SharePrefix = @"\\";           
 const string DIR = @"\";
 const char  cDIR = '\\';
 const string DIRDOUBLE = @"\\";
 const string COLONDIR = @":\";
 const string COLON = @":";
 const char cCOLON = ':';
 const string DIRSPACE = @"\ ";
 const string SPACEDIR = @" \";
 const string SPACE = @" ";

 public static int IndexOfOccurence(this string s, char match, int occurence)
 {
  int i = 1;
  int index = -1;

  while (i <= occurence && (index = s.IndexOf(match, index + 1)) != -1)
  {
   if (i == occurence)
    return index;

   i++;
  }

  return -1;
 }
 
 /// <summary>
 /// Gets UNC Host and Share from a full UNC path. Cuts 4th backslash from start of path, must have least 1 char between.
 /// </summary>
 /// <param name="UNCFullPath">\\host\share returns empty, must end in a backslash</param>
 /// <returns>\\host\share from \\host\share\tail\, also \\?\UNC\ and \\?\ work</returns>
 /// <warn>//fails for one case when "\\?\UNC\share\tail\file.txt", UNC Server Name is named "UNC"</warn>
 /// <author>Metadataconsulting.blogspot.com</warn>
    public static string GetUNCHostShare(this string UNCFullPath)
 {
  if (UNCFullPath.StartsWith(DIRDOUBLE))
  {
   string p = UNCFullPath; //local working copy
   
   if (p.StartsWith(ShareExtPrefix))
   {
    p = p.Substring(3, p.Length - 3);
    
    if (p.StartsWith(@"\UNC\")) //fails for "\\?\UNC\share\tail\file.txt" one case
     p = DIRDOUBLE + p.Substring(5, p.Length - 5);
    else
     p = DIR + p;
   } 
   
   //starts with \\h\s is min 
   int idx3rd = (p.Length >= 5 ) ? p.IndexOf(cDIR, 3) : -1; //4th position zero index 

   //Console.WriteLine("p = " + p + " idx3rd=" + idx3rd); //DEBUG

   if (p[0]==cDIR && p[1]==cDIR && Char.IsLetter(p[2]) && p.Length >= 5 &&idx3rd > -1 && Char.IsLetter(p[idx3rd+1]) && p.IndexOf(cDIR, idx3rd + 2) > -1)
   {
    int i = p.IndexOfOccurence(cDIR, 4);

    if (i > -1)
     return p.Substring(0, i); //returns empty if i=0
    else
     return string.Empty;

   }
   else
    return string.Empty;
   
   

  }
  else
   return string.Empty;

 }

 public static void Main()
 {
   Console.WriteLine(@"\\host\share\tail\dir1".GetUNCHostShare());
   Console.WriteLine(@"\\host\share\tail\file.txt".GetUNCHostShare());
         Console.WriteLine(@"\\\?\UNC\share\tail\file.txt".GetUNCHostShare());
         Console.WriteLine(@"\\h\s\file.txt".GetUNCHostShare());
         Console.WriteLine(@"\\h\s\".GetUNCHostShare());
         Console.WriteLine(@"\\\s\".GetUNCHostShare());
         Console.WriteLine(@"\\h\\".GetUNCHostShare());
         Console.WriteLine(@"\\\\\\\\".GetUNCHostShare());
         Console.WriteLine(@"\\?\UNC\share\tail\file.txt".GetUNCHostShare() + ", 1 failed case - UNC is Server Name");
   
 }
}


Tuesday, February 26, 2019

Speed tests of C# replace a character in a string "ReplaceAt" string extension methods

Below are some speed tests of common C# method to replace a character in a string "ReplaceAt". There are three types listed. A Linq version, a ToCharArray() version and a pure string manipulation version.

Update 05-Sep-19  -  See fastest UNICODE ersion https://metadataconsulting.blogspot.com/2019/08/C-Sharp-A-Faster-Unicode-ReplaceAt-method-that-works-with-surrogate-pairs-and-4-byte-Unicode-characters.html



using System.Linq; 
using System.Diagnostics;
using System;


     
public static class Program
{
 public static string ReplaceAtStringManipulation(this string s, int idx, char replaceChar)
    {
  if (string.IsNullOrEmpty(s) || idx >= s.Length || idx < 0) 
                    return s; 
 
        return s.Remove(idx, 1).Insert(idx, replaceChar.ToString());
    }
 
 public static string ReplaceAtLinq(this string value, int index, char newchar)
 {
  if (value.Length <= index)
   return value;
  else
   return string.Concat(value.Select((c, i) => i == index ? newchar : c));
 }

 public static string ReplaceAtCharArray(this string input, uint index, char newChar)
 {
  if (string.IsNullOrEmpty(input) || index >= input.Length) 
   return input;

  char[] chars = input.ToCharArray();
  chars[index] = newChar;
  return new string(chars);
 }

 public static void Main()
 {
  Stopwatch sw = new Stopwatch();
  sw.Start();
  Console.WriteLine("ReplaceAtCharArraySSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSs".ReplaceAtCharArray(70,'X')); 
  sw.Stop();
  Console.WriteLine("in {0} ticks.",sw.ElapsedTicks.ToString("N0")); 
  
  sw.Restart();
  Console.WriteLine("ReplaceAtLinqSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS".ReplaceAtLinq(70,'Y')); 
  sw.Stop();
  Console.WriteLine("in {0} ticks.",sw.ElapsedTicks.ToString("N0")); 
  
  sw.Restart();
  Console.WriteLine("ReplaceAtStringManipulationSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS".ReplaceAtStringManipulation(70,'Z')); 
  sw.Stop();
  Console.WriteLine("in {0} ticks.",sw.ElapsedTicks.ToString("N0")); 
  
 }
}

Monday, February 25, 2019

A more forgiving c# replace a character in a string extension method ReplaceAt

Lately, I have seen this function replicated all over the inter-webs, all without some basic bounds checking. 

Here's a more forgiving C# replace a character in a string "ReplaceAt" string extension method.

Update Thu 05-Sep-19 - See full UNICODE version - https://metadataconsulting.blogspot.com/2019/08/C-Sharp-A-Faster-Unicode-ReplaceAt-method-that-works-with-surrogate-pairs-and-4-byte-Unicode-characters.html


        /// <summary>
        /// Change a character in string, using zero-based char[]. This implementation is faster than string builder.
        /// </summary>
        /// <param name="s">input string</param>
        /// <param name="idx">index</param>
        /// <param name="replaceChar">replacement character</param>
        /// <returns></returns>
        public static string ReplaceAt(this string s, uint idx, char replaceChar)
        {
            if (string.IsNullOrEmpty(s) || idx >= s.Length)
                return s;

            char[] chars = s.ToCharArray();
            chars[idx] = replaceChar;
            return new string(chars);
        }