Check whenever string is valid path - c#

I'm trying to use Uri.IsWellFormedUriString but it doesn't work, and question is - why:
class Program
{
static void Main()
{
Console.WriteLine(IsWellFormed(#"C:\Windows"));
Console.WriteLine(IsWellFormed(#"C:\\:\\//Windows32"));
}
public static bool IsWellFormed(string path)
{
string uriString = "file:///" + path;
string wellFormed = uriString.Replace('\\', '/');
return Uri.IsWellFormedUriString(wellFormed, UriKind.Absolute);
}
}
expected true false output but it returns true in both cases. And I'm really confused a bit.

Here is an approach without try/catch, though it may not be optimal:
public static bool IsWellFormed(string path)
{
string path = "C:\\windows\\:ppz";
var isRooted = Path.IsPathRooted(path);
var root = Path.GetPathRoot(path);
var list = path.Split(new char[] {Path.DirectorySeparatorChar}, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < list.Length; i ++)
{
if(i == 0 && isRooted && s[i]+"\\" == root) continue;
if (s[i].Intersect(Path.GetInvalidPathChars()).Count() != 0)
return false;
if (s[i].Intersect(Path.GetInvalidFileNameChars()).Count() != 0)
return false;
}
return true;
}
You can play with your values and see if this fits your task. You can also customize your own lists for invalid chars.

Related

Check the difference

Hi I'm building a program that will look at files at have been placed into SVN and show what files have been changed in each commit.
As i'm only wanting to show the file path. if the path is that same I only want to show the difference.
example:
First file path is:
/GEM4/trunk/src/Tools/TaxMarkerUpdateTool/Tax Marker Ripper v1/DataModifier.cs
Second file path is:
/GEM4/trunk/src/Tools/TaxMarkerUpdateTool/Tax Marker Ripper v1/Tax Marker Ripper v1.csproj
What I'd like to do is substring at the point of difference.
So in this case:
/GEM4/trunk/src/Tools/TaxMarkerUpdateTool/Tax Marker Ripper v1/
would be substringed
I hope this helps:
public string GetString(string Path1, string Path2)
{
//Split and Put everything between / in the arrays
string[] Arr_String1 = Path1.Split('/');
string[] Arr_String2 = Path2.Split('/');
string Result = "";
for (int i = 0; i <= Arr_String1.Length; i++)
{
if (Arr_String1[i] == Arr_String2[i])
{
//Puts the Content that is the same in an Result string with /
Result += Arr_String1[i] + '/';
}
else
break;
}
// If Path is identical he would add a / which we dont want
if (Result.Contains('.'))
{
Result = Result.TrimEnd('/');
}
return Result;
}
You can do this pretty easily with a loop. Basically:
public String FindCommonStart(string a, string b)
{
int length = Math.Min(a.Length, b.Length);
var common = String.Empty;
for (int i = 0; i < length; i++)
{
if (a[i] == b[i])
{
common += a[i];
}
else
{
break;
}
}
return common;
}
Something like this:
public string GetCommonStart(string a, string b)
{
if ((a == null) || (b == null))
throw new ArgumentNullException();
int Delim = 0;
int I = 0;
while ((I < a.Length) && (I < b.Length) && (a[I] == b[I]))
{
if (a[I++] == Path.AltDirectorySeparatorChar) // or Path.DirectorySeparatorChar
Delim = I;
}
return a.Substring(0, Delim);
}
Keep in mind, that this code is case-sensitive (and paths in windows in general are not).

Resharper Search with pattern method call

I want to replace this part of code using "Search with pattern...":
public bool IsDbObjectsOK()
{
var result = 0;
result = usp_IsDbObjectsOK();
if (result == 0)
return true;
return false;
}
public bool UnlockWindow()
{
var result = 0;
result = usp_UnlockWindow();
if (result == 0)
return true;
return false;
}
Replace with:
public bool IsDbObjectsOK()
{
return usp_IsDbObjectsOK() == 0;
}
public bool UnlockWindow()
{
return usp_UnlockWindow() == 0;
}
I tried to use
var $result$ = 0;
$result$ = $usp_IsDbObjectsOK$();
if ($result$ == 0)
return true;
return false;
This doesn't work, because the method call isn't found in any of the code that needs to be replaced.
How to do this?
You need to make sure that you use the correct placeholder type when you set up the search.
Here, result should be an Identifier Placeholder and usp_IsDbObjectsOK should be an Expression Placeholder. When I do that, the replace works as you'd expect.

XML - System.Xml.XmlException - hexadecimal value 0x06

I get this error. Later I searched and found out the reason of illegal characters in my XML and its solution. But I don't have the access to edit any of these files. My job is to read and fetch the tag value, attribute value and similar stuff. SO I can't replace the binary characters with escapes like '\x01' with &#01. Also I tried to include CheckCharacters =false in XMLreader settings. It doesn't take this. Still it is throwing the same error.
Is it not possible to fix in XMLreader? I read about XMLtextReader. It can skip the exception. But already I have coded for all my features using XMLreader. It would be good if I can find a solution for this. Otherwise I would have to change all my code.
My code:
private void button1_Click(object sender, EventArgs e)
{
int i = 0;
var filenames = System.IO.Directory
.EnumerateFiles(textBox1.Text, "*.xml", System.IO.SearchOption.AllDirectories)
.Select(System.IO.Path.GetFullPath);
foreach (var f in filenames)
{
var resolver = new XmlUrlOverrideResolver();
resolver.DtdFileMap[#"X1.DTD"] = #"\\location\X1.DTD";
resolver.DtdFileMap[#"R2.DTD"] = #"\\location\X2.DTD";
resolver.DtdFileMap[#"R5.DTD"] = #"\\location\R5.DTD";
XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Parse;
settings.XmlResolver = resolver;
XmlReader doc = XmlReader.Create(f, settings);
while (doc.Read())
{
if ((doc.NodeType == XmlNodeType.Element) && (doc.Name == "ap"))
{
if (doc.HasAttributes)
{
String fin = doc.GetAttribute("ap");
if (fin == "no")
{
String[] array = new String[10000];
array[i] = (f);
File.AppendAllText(#"\\location\NAPP.txt", array[i] + Environment.NewLine);
i++;
}
else
{
String[] abs = new String[10000];
abs[i] = (f);
File.AppendAllText(#"\\location\APP.txt", abs[i] + Environment.NewLine);
i++;
}
}
}
}
}
MessageBox.Show("Done");
}
This is a very simple example of character "filter" that will replae the 0x06 character with a space:
public class MyStreamReader : StreamReader {
public MyStreamReader(string path)
: base(path) {
}
public override int Read(char[] buffer, int index, int count) {
int res = base.Read(buffer, index, count);
for (int i = 0; i < res; i++) {
if (buffer[i] == 0x06) {
buffer[i] = ' ';
}
}
return res;
}
}
You use it this way:
using (var sr = new MyStreamReader(f)) {
var doc = XmlReader.Create(sr, settings);
Note that it's very simple because it's replacing a character (the 0x06) with another character of the same "length" (the space). If you wanted to replace a character with a "sequence" of characters (to escape it), it would get more complex (not impossible, 30 minutes of work difficult)
(I have checked and it seems the XmlTextReader only uses that method and not the Read() method)
As always, when a programmer tells you 30 minutes, it means 0 minutes or 2 hours :-)
This is the "more complex" ReplacingStreamReader:
/// <summary>
/// Only the Read methods are supported!
/// </summary>
public class ReplacingStreamReader : StreamReader
{
public ReplacingStreamReader(string path)
: base(path)
{
}
public Func<char, string> ReplaceWith { get; set; }
protected char[] RemainingChars { get; set; }
protected int RemainingCharsIndex { get; set; }
public override int Read()
{
int ch;
if (RemainingChars != null)
{
ch = RemainingChars[RemainingCharsIndex];
RemainingCharsIndex++;
if (RemainingCharsIndex == RemainingChars.Length)
{
RemainingCharsIndex = 0;
RemainingChars = null;
}
}
else
{
ch = base.Read();
if (ch != -1)
{
string replace = ReplaceWith((char)ch);
if (replace == null)
{
// Do nothing
}
else if (replace.Length == 1)
{
ch = replace[0];
}
else
{
ch = replace[0];
RemainingChars = replace.ToCharArray(1, replace.Length - 1);
RemainingCharsIndex = 0;
}
}
}
return ch;
}
public override int Read(char[] buffer, int index, int count)
{
int res = 0;
// We leave error handling to the StreamReader :-)
// We handle only "working" parameters
if (RemainingChars != null && buffer != null && index >= 0 && count > 0 && index + count <= buffer.Length)
{
int remainingCharsCount = RemainingChars.Length - RemainingCharsIndex;
res = Math.Min(remainingCharsCount, count);
Array.Copy(RemainingChars, RemainingCharsIndex, buffer, index, res);
RemainingCharsIndex += res;
if (RemainingCharsIndex == RemainingChars.Length)
{
RemainingCharsIndex = 0;
RemainingChars = null;
}
if (res == count)
{
return res;
}
index += res;
count -= res;
}
while (true)
{
List<char> sb = null;
int res2 = base.Read(buffer, index, count);
if (res2 == 0 || ReplaceWith == null)
{
return res;
}
int j = 0;
for (int i = 0; i < res2; i++)
{
char ch = buffer[index + i];
string replace = ReplaceWith(ch);
if (sb != null)
{
if (replace == null)
{
sb.Add(ch);
}
else
{
sb.AddRange(replace);
}
}
else if (replace == null)
{
buffer[j] = ch;
j++;
}
else if (replace.Length == 1)
{
buffer[j] = replace[0];
j++;
}
else if (replace.Length == 0)
{
// We do not advance
}
else
{
sb = new List<char>();
sb.AddRange(replace);
}
}
res2 = j;
if (sb != null)
{
int res3 = Math.Min(sb.Count, count - res2);
sb.CopyTo(0, buffer, index + res2, res3);
if (res3 < sb.Count)
{
RemainingChars = new char[sb.Count - res3];
RemainingCharsIndex = 0;
sb.CopyTo(res3, RemainingChars, 0, RemainingChars.Length);
}
res += res3;
}
else
{
res2 = j;
// Can't happen if sb != null (at least a character must
// have been added)
if (res2 == 0)
{
continue;
}
}
res += res2;
return res;
}
}
}
Use it like:
using (var sr = new ReplacingStreamReader(f))
{
sr.ReplaceWith = x =>
{
return x == 0x6 ? " " : null;
// return x == '.' ? " " : null; // Replace all . with
};
var doc = XmlReader.Create(sr, settings);
Be aware that the ReplacingStreamReader doesn't "know" which part of the xml it is modifying, so rarely a "blind" replace is ok :-) Other than this limitation, you can replace any character with any string (null in the ReplaceWith means "keep the current character", equivalent to x.ToString() in the example given. Returning string.Empty is valid, means remove the current character).
The class is quite interesting: it keeps a char[] RemainingChars with the chars that have been read (and filtered by ReplaceWith) but that haven't been returned by a Read() method because the passed buffer was too much small (the ReplaceWith method could "enlarge" the read string, making it too much big for the buffer!). Note that sb is a List<char> instead of a StringBuilder. Probably using one or the other would be nearly equivalent, code-wise.
You could first read the content into a string replace (escape) the content, and then load it into a XmlReader:
foreach (var f in filenames) {
string text;
using (StreamReader s = new StreamReader(f,Encoding.UTF8)) {
text = s.ReadToEnd();
}
text = text.Replace("\x01",#"&#01"); //replace the content
//load some settings
var resolver = new XmlUrlOverrideResolver();
resolver.DtdFileMap[#"X1.DTD"] = #"\\location\X1.DTD";
resolver.DtdFileMap[#"R2.DTD"] = #"\\location\X2.DTD";
resolver.DtdFileMap[#"R5.DTD"] = #"\\location\R5.DTD";
XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Parse;
settings.XmlResolver = resolver;
XmlReader doc = XmlReader.Create(text, settings);
//perform processing task
//...
}

Check if array is null and has content

I'm in search for some code-improvement. I currently have the following piece of code:
if (pMyDocAction.s_locatie_st != null)
{
String[] myLocaties = Globals.GlobalTools.DeserializeValueToStringArray(pMyDocAction.s_locatie_st);
if (myLocaties != null)
if (myLocaties.Length > 0)
row.Locatie = myLocaties[0];
else
row.Locatie = String.Empty;
else
row.Locatie = String.Empty;
}
else
row.Locatie = String.Empty;
Mylocaties is a Array of String and this cannot change. How can i shorten this piece of code (or how can i combine the != null and .length > 0?
Thnx
You can use conditional operator and write that statement like this:
row.Locatie = (myLocaties != null &&
myLocaties.Length > 0) ? myLocaties[0] : String.Empty
I would suggest you to create a small extension method:
public static class ArrayExtension{
public static bool HasContent<T>(Array<T> array) {
return array != null && array.Length > 0;
}
}
Then you can check :
int[] x = null;
x.HasContent(); // false
string[] strs = new string[] {};
strs.HasContent(); // false
string[] strs2 = new string[] {"foo", "bar" };
strs.HasContent(); // true
This can be extended to simplify your syntax:
public static class ArrayExtension{
public static T FirstValueOrDefault<T>(Array<T> array, T #default) {
if( array != null && array.Length >0 ){
return array[0];
}
else {
return #default;
}
}
}
int[] x = null;
int y = x.FirstValueOrDefault(42); // 42
string[] strs = new string[] {};
string some = strs.FirstValueOrDefault("default"); // default
string[] strs2 = new string[] {"foo", "bar" };
string some2 = strs.FirstValueOrDefault("default"); // foo
Use && operator on two conditions, it will do short-circuit evaluation and if first condition is false, it will not evaluate the second condition.
if (myLocaties != null && myLocaties.Length > 0)
{
row.Locatie = myLocaties[0];
}
else
{
row.Locatie = String.Empty;
}
Since all other answers seem to ignore the if (pMyDocAction.s_locatie_st != null), something like this seems to be the most reusable:
row.Locatie = DeserializeLocation(pMyDocAction.s_locatie_st);
string DeserializeLocation(string locationString)
{
var result = "";
if (!string.IsNullOrEmpty(locationString))
{
String[] deserializedLocations =
Globals.GlobalTools.DeserializeValueToStringArray(locationString);
if (deserializedLocations != null && deserializedLocations.Any())
{
result = deserializedLocations[0];
}
}
return result;
}
You might even consider putting this method in your "GlobalTools" class, so you can call it from anywhere were you need to deserialize a potentially null-bearing serialized location string into a location string.

Trying to loop HttpWebRequest with no success

I am trying to create a program which can sort the number of results associated with any specified google search. I need a big table very fast so I thought about using a loop. Each time I try it though, the debugger crashes due to a "System.Windows.Markup.XamlParseException".
public long resultStat(string a)
{
var req = (HttpWebRequest)WebRequest.Create("https://www.google.ca/search?hl=fr&output=search&sclient=psy-ab&q=a" + a + "&btnK=");
using (req as IDisposable)
{
WebResponse rep = req.GetResponse();
Stream str = rep.GetResponseStream();
StreamReader rdr = new StreamReader(str);
string res = rdr.ReadToEnd();
rdr.Close();
//This is my code to get the number results (it works perfectly)
int index = res.IndexOf(">Environ");
int cond = 0;
string final = "";
try
{
while (res[++index] != '<')
{
if (cond-- == 0 && res[index] != '&')
{ final += res[index]; cond = 0; }
else if (res[index] == '&') cond = 5;
}
}
catch { return 0; }
string temp = "";
foreach (char i in final) if (i < 48 && i > 58) temp += i;
return Int64.Parse(temp);
}
}
This whole method is simply used in the main in a for loop such as :
public void main()
{
//Other code
for (int i = 0; i < 3; i++) resultStat(i.ToString()); // For example
//Other code
}
I know it's the problem because as soon as I comment the loop, or lower it to one rep, nothing goes wrong. I've tried:
HttpWebRequest().Abort();
HttpWebRequest().KeepAlive = false;
It didn't work
I don't think the away you are doing is the correct way to do this. The simple one i can tell you is use Lib curl c#. You can send in an array of urls and get response as an array. That would be perfect for what you require here. Here is a sample class code below that does the multitasking itself. You just send in the urls.
public class MultiHttp
{
public static string UserAgent = "Mozilla 5.0";
public static string Header = "Content-Type: application/x-www-form-urlencoded; charset=UTF-8";
private static string[] Result;
public static string[] MultiPost(string[] Url, string post, int timeOut)
{
Result = new string[post.Length];
try
{
Curl.GlobalInit((int)CURLinitFlag.CURL_GLOBAL_ALL);
Easy.WriteFunction wf = new Easy.WriteFunction(OnWriteData);
//Easy.HeaderFunction hf = new Easy.HeaderFunction(OnHeaderData);
Easy[] easy = new Easy[Url.Length];
Multi multi = new Multi();
for (int i = 0; i < Url.Length; i++)
{
if (Url[i] != null)
{
easy[i] = new Easy();
easy[i].SetOpt(CURLoption.CURLOPT_URL, Url[i]);
easy[i].SetOpt(CURLoption.CURLOPT_WRITEFUNCTION, wf);
easy[i].SetOpt(CURLoption.CURLOPT_WRITEDATA, i);
//easy[i].SetOpt(CURLoption.CURLOPT_HEADERFUNCTION, hf);
//easy[i].SetOpt(CURLoption.CURLOPT_HEADERDATA, i);
easy[i].SetOpt(CURLoption.CURLOPT_TIMEOUT, timeOut);
easy[i].SetOpt(CURLoption.CURLOPT_USERAGENT, UserAgent);
Slist sl = new Slist();
sl.Append(Header);
easy[i].SetOpt(CURLoption.CURLOPT_HTTPHEADER, sl);
easy[i].SetOpt(CURLoption.CURLOPT_POSTFIELDS, post);
easy[i].SetOpt(CURLoption.CURLOPT_FOLLOWLOCATION, true);
easy[i].SetOpt(CURLoption.CURLOPT_POST, true);
//easy[i].SetOpt(CURLoption.CURLOPT_NOBODY, true);
if (Url[i].Contains("https"))
{
easy[i].SetOpt(CURLoption.CURLOPT_SSL_VERIFYHOST, 1);
easy[i].SetOpt(CURLoption.CURLOPT_SSL_VERIFYPEER, 0);
}
multi.AddHandle(easy[i]);
}
}
int stillRunning = 1;
while (multi.Perform(ref stillRunning) == CURLMcode.CURLM_CALL_MULTI_PERFORM) ;
while (stillRunning != 0)
{
multi.FDSet();
int rc = multi.Select(1000); // one second
switch (rc)
{
case -1:
stillRunning = 0;
break;
case 0:
default:
{
while (multi.Perform(ref stillRunning) == CURLMcode.CURLM_CALL_MULTI_PERFORM) ;
break;
}
}
}
// various cleanups
multi.Cleanup();
for (int i = 0; i < easy.Length; i++)
{
easy[i].Cleanup();
}
Curl.GlobalCleanup();
}
catch (Exception)
{
//r = ex+"";
}
return Result;
}
public static Int32 OnWriteData(Byte[] buf, Int32 size, Int32 nmemb,
Object extraData)
{
int tmp = Convert.ToInt32(extraData.ToString()); ;
Result[tmp] += System.Text.Encoding.UTF8.GetString(buf);
return size * nmemb;
}
}
Call it like :
String[] url= new String[2];
url[1]="https://www.google.ca/search?hl=fr&output=search&sclient=psy-ab&q=a1&btnK=";
url[2]="https://www.google.ca/search?hl=fr&output=search&sclient=psy-ab&q=a2&btnK=";
string postString=""; // IF YOU DO NOT WANT TO POST ANYTHING YOU CAN DO THE SAME THING KEEP URL THE SAME SEND POST ARRAY AND CHANGE THE CLASS IT WORKS BOTH WAYS
String[] result = MultiHttp.MultiPost(url, postString, timeOut);
Its just a sample but will get you the working idea to sort out your problem.

Categories

Resources