Evaluate escaped string - c#

I have some strings in a file that are already escaped. So the content of the file looks like this:
Hello\nWorld. This is\tGreat.
When I read the file, I get \n as two different characters instead of one.
How can I convert an escaped string to a non-escaped one?

based on #deAtog 's code, i made some minor additions
support \U00000000 format chars
simplify the hex conversions somewhat
string UnEscape(string s)
{
StringBuilder sb = new StringBuilder();
Regex r = new Regex("\\\\[abfnrtv?\"'\\\\]|\\\\[0-3]?[0-7]{1,2}|\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}|.");
MatchCollection mc = r.Matches(s, 0);
foreach (Match m in mc)
{
if (m.Length == 1)
{
sb.Append(m.Value);
}
else
{
if (m.Value[1] >= '0' && m.Value[1] <= '7')
{
int i = Convert.ToInt32(m.Value.Substring(1), 8);
sb.Append((char)i);
}
else if (m.Value[1] == 'u')
{
int i = Convert.ToInt32(m.Value.Substring(2), 16);
sb.Append((char)i);
}
else if (m.Value[1] == 'U')
{
int i = Convert.ToInt32(m.Value.Substring(2), 16);
sb.Append(char.ConvertFromUtf32(i));
}
else
{
switch (m.Value[1])
{
case 'a':
sb.Append('\a');
break;
case 'b':
sb.Append('\b');
break;
case 'f':
sb.Append('\f');
break;
case 'n':
sb.Append('\n');
break;
case 'r':
sb.Append('\r');
break;
case 't':
sb.Append('\t');
break;
case 'v':
sb.Append('\v');
break;
default:
sb.Append(m.Value[1]);
break;
}
}
}
}
return sb.ToString();
}

You can try using System.Text.RegularExpressions.Regex.Unescape.
There's also an entry on the MSDN forums.
See also How can I Unescape and Reescape strings in .net? .

Like you I was unable to find a decent solution to this problem. While you can certainly use String.Replace, the performance and speed of this solution is terrible. Furthermore, it's hard to support octal and Unicode escape sequences via this method. A much better alternative is to use a simple RegEx parser. Here's a method that will properly un-escape any string given. It supports standard escape sequences, octal escape sequences, and unicode escape sequences.
string UnEscape(string s) {
StringBuilder sb = new StringBuilder();
Regex r = new Regex("\\\\[abfnrtv?\"'\\\\]|\\\\[0-3]?[0-7]{1,2}|\\\\u[0-9a-fA-F]{4}|.");
MatchCollection mc = r.Matches(s, 0);
foreach (Match m in mc) {
if (m.Length == 1) {
sb.Append(m.Value);
} else {
if (m.Value[1] >= '0' && m.Value[1] <= '7') {
int i = 0;
for (int j = 1; j < m.Length; j++) {
i *= 8;
i += m.Value[j] - '0';
}
sb.Append((char)i);
} else if (m.Value[1] == 'u') {
int i = 0;
for (int j = 2; j < m.Length; j++) {
i *= 16;
if (m.Value[j] >= '0' && m.Value[j] <= '9') {
i += m.Value[j] - '0';
} else if (m.Value[j] >= 'A' && m.Value[j] <= 'F') {
i += m.Value[j] - 'A' + 10;
} else if (m.Value[j] >= 'a' && m.Value[j] <= 'f') {
i += m.Value[j] - 'a' + 10;
}
}
sb.Append((char)i);
} else {
switch (m.Value[1]) {
case 'a':
sb.Append('\a');
break;
case 'b':
sb.Append('\b');
break;
case 'f':
sb.Append('\f');
break;
case 'n':
sb.Append('\n');
break;
case 'r':
sb.Append('\r');
break;
case 't':
sb.Append('\t');
break;
case 'v':
sb.Append('\v');
break;
default:
sb.Append(m.Value[1]);
break;
}
}
}
}
return sb.ToString();
}

you could do something like:
string str = str.Replace(#"\n","\n");
update:
Obviously this is a workaround as the scenario is "un natural" by itself. The Regex.Unescape solution is unapplicable here as it is intended to use for unescaping regex control characters, and not new lines etc.
In order to support other relevant characters one can write a replacing function like this one:
public string ReEscapeControlCharacters(string str) {
return str.Replace(#"\n","\n").Replace(#"\r","\r").Replace(#"\t","\t");
}

Try this:
String replaced = startstring.Replace(System.Environment.NewLine, desirevalue);
This have to be valid only for "\n".

Related

Converting if statements to switch but not working, where did conversion go wrong? [duplicate]

This question already has answers here:
Switch case: can I use a range instead of a one number [duplicate]
(16 answers)
Multiple cases in switch statement
(24 answers)
Closed 1 year ago.
This is part of the code, it gets a line of numbers from a textfile and counts how many numbers fit in each specified range. I'm converting it from if, else if statements (which works fine) just for practice. However none of the numbers are counting except 1, the highest number in the textfile, which fits in the default of this switch. Where did I go wrong?
int i = 0;
switch (students[i].Grade)
{
case 1:
{
if(students[i].Grade <= 59)
distributions[0] += 1;
break;
}
case 2:
{
if(students[i].Grade >= 60 && students[i].Grade <= 69)
distributions[1] += 1;
break;
}
case 3:
{
if(students[i].Grade >= 70 && students[i].Grade <= 79)
distributions[2] += 1;
break;
}
case 4:
{
if (students[i].Grade >= 80 && students[i].Grade <= 89)
distributions[3] += 1;
break;
}
// students with grade of 90 or above
default:
{
distributions[4] += 1;
break;
}
}
Console.WriteLine("0-59: {0}\n60-69: {1}\n70-79: {2}\n80-89: {3}\n90-100: {4}", distributions[0], distributions[1], distributions[2], distributions[3], distributions[4]);
this is the code using if else if statements, works fine.
for (int i = 0; i < students.Length; i++)
if (students[i].Grade <= 59)
{
distributions[0] += 1;
}
else if (students[i].Grade >= 60 && students[i].Grade <= 69)
{
distributions[1] += 1;
}
else if (students[i].Grade >= 70 && students[i].Grade <= 79)
{
distributions[2] += 1;
}
else if (students[i].Grade >= 80 && students[i].Grade <= 89)
{
distributions[3] += 1;
}
//students with grade of 90 or above
else
{
distributions[4] += 1;
}
Console.WriteLine("0-59: {0}\n60-69: {1}\n70-79: {2}\n80-89: {3}\n90-100: {4}", distributions[0], distributions[1], distributions[2], distributions[3], distributions[4]);
if you use c# 7+ you can try this
for (int i = 0; i < students.Length; i++)
switch (students[i].Grade)
{
case int n when (n <=59):
distributions[0] += 1;
break;
case int n when (n >= 60 && n <= 69):
distributions[1] += 1;
break;
.... and so on
}
The switch statement compares the value in students[i].Grade with each integer, which is behind the word "case".
So case 1: compares the students[i].Grade with 1 and that is never true. 2,3 and 4 does nobody have too, so it always goes in the default case.
So switch expression here is not a good idea, because you can not catch interval in a "case"
You can use a new C# 9.0 pattern matching feature allowing you to combine patterns with and and or
switch (students[i].Grade) {
case <= 59:
distributions[0] += 1;
break;
case >= 60 and <= 69:
distributions[1] += 1;
break;
case >= 70 and <= 79:
distributions[2] += 1;
break;
case >= 80 and <= 89:
distributions[3] += 1;
break;
default:
distributions[4] += 1;
break;
}
But you can simplify the logic a bit. E.g. you don't have to test for grade >= 60, since the cases are evaluated in order and the case <= 59 has already been tested (this is true for the if-else solution as well)
switch (students[i].Grade) {
case < 60:
distributions[0] += 1;
break;
case < 70:
distributions[1] += 1;
break;
case < 80:
distributions[2] += 1;
break;
case < 90:
distributions[3] += 1;
break;
default:
distributions[4] += 1;
break;
}
Note that if Grade is an int then <= 59 is equivalent to < 60. I used the second one as it looks nicer.
Yet another simplification can be achieved with the new switch expression (C# 8.0):
int index = students[i].Grade switch {
< 60 => 0,
< 70 => 1,
< 80 => 2,
< 90 => 3,
_ => 4
};
distributions[index] += 1;

how to convert series of integers into ordinals in C#

i am having a texbox1 with series of integers i would like to know if their is any way i can apply the conversion of these integers into ordinals. below is what i have tried:
when my button convert is clicked with code:
private void btnconvert_Click(object sender, RoutedEventArgs e)
{
foreach (int num in txtresults.ToString())
{
string[] parts = txtresults.Text.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
double[] numbers = parts.Select(p => double.Parse(p)).ToArray();
double maximum = numbers.Max();
int position = Array.IndexOf(numbers, maximum);
parts[position] = **Ordinal(num);**
txtresults.Text = string.Join(" ", parts);
}
}
this is my method of conversion
public static string **Ordinal(int num)**
{
if (num <= 0) return num.ToString();
switch (num % 100)
{
case 11:
case 12:
case 13:
return num + "th";
}
switch (num % 10)
{
case 1:
return num + "st";
case 2:
return num + "nd";
case 3:
return num + "rd";
default:
return num + "th";
}
}
can i be thought how to do it right please (thanks in advance) (am using c# in wpf)

Is there a Java equivalent for C#'s HttpServerUtility.UrlTokenDecode?

How do I decode in Java a string that was encoded in C# using HttpServerUtility.UrlTokenEncode?
I tried using org.apache.commons.codec.binary.Base64 (The ctor accepts a parameter stating whether the encoding/decoding is url-safe) but turns out it is not implemented the same as UrlTokenEncode/Decode.
I ended up migrating the C# implementation to Java:
public static byte[] UrlTokenDecode(String input) {
if (input == null)
return new byte[0];
int len = input.length();
if (len < 1)
return new byte[0];
///////////////////////////////////////////////////////////////////
// Step 1: Calculate the number of padding chars to append to this string.
// The number of padding chars to append is stored in the last char of the string.
int numPadChars = (int)input.charAt(len - 1) - (int)'0';
if (numPadChars < 0 || numPadChars > 10)
return null;
///////////////////////////////////////////////////////////////////
// Step 2: Create array to store the chars (not including the last char)
// and the padding chars
char[] base64Chars = new char[len - 1 + numPadChars];
////////////////////////////////////////////////////////
// Step 3: Copy in the chars. Transform the "-" to "+", and "*" to "/"
for (int iter = 0; iter < len - 1; iter++) {
char c = input.charAt(iter);
switch (c) {
case '-':
base64Chars[iter] = '+';
break;
case '_':
base64Chars[iter] = '/';
break;
default:
base64Chars[iter] = c;
break;
}
}
////////////////////////////////////////////////////////
// Step 4: Add padding chars
for (int iter = len - 1; iter < base64Chars.length; iter++) {
base64Chars[iter] = '=';
}
// Do the actual conversion
String assembledString = String.copyValueOf(base64Chars);
return Base64.decodeBase64(assembledString);
}

Most light weight conversion from hex to byte in c#? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How do you convert Byte Array to Hexadecimal String, and vice versa?
I need an efficient and fast way to do this conversion. I have tried two different ways, but they are not efficient enough for me. Is there any other quick method to accomplish this in a real-time fashion for an application with huge data?
public byte[] StringToByteArray(string hex)
{
return Enumerable.Range(0, hex.Length / 2).Select(x => Byte.Parse(hex.Substring(2 * x, 2), NumberStyles.HexNumber)).ToArray();
}
The above one felt more efficient to me.
public static byte[] stringTobyte(string hexString)
{
try
{
int bytesCount = (hexString.Length) / 2;
byte[] bytes = new byte[bytesCount];
for (int x = 0; x < bytesCount; ++x)
{
bytes[x] = Convert.ToByte(hexString.Substring(x * 2, 2), 16);
}
return bytes;
}
catch
{
throw;
}
If you really need efficiency then:
Don't create substrings
Don't create an iterator
Or, and get rid of try blocks which only have a catch block which rethrows... for simplicity rather than efficiency though.
This would be a pretty efficient version:
public static byte[] ParseHex(string hexString)
{
if ((hexString.Length & 1) != 0)
{
throw new ArgumentException("Input must have even number of characters");
}
int length = hexString.Length / 2;
byte[] ret = new byte[length];
for (int i = 0, j = 0; i < length; i++)
{
int high = ParseNybble(hexString[j++]);
int low = ParseNybble(hexString[j++]);
ret[i] = (byte) ((high << 4) | low);
}
return ret;
}
private static int ParseNybble(char c)
{
// TODO: Benchmark using if statements instead
switch (c)
{
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
return c - '0';
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
return c - ('a' - 10);
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
return c - ('A' - 10);
default:
throw new ArgumentException("Invalid nybble: " + c);
}
return c;
}
The TODO refers to an alternative like this. I haven't measured which is faster.
private static int ParseNybble(char c)
{
if (c >= '0' && c <= '9')
{
return c - '0';
}
c = (char) (c & ~0x20);
if (c >= 'A' && c <= 'F')
{
return c - ('A' - 10);
}
throw new ArgumentException("Invalid nybble: " + c);
}
I took the benchmarking code from the other question, and reworked it to test the hex to bytes methods given here:
HexToBytesJon: 36979.7 average ticks (over 150 runs)
HexToBytesJon2: 35886.4 average ticks (over 150 runs)
HexToBytesJonCiC: 31230.2 average ticks (over 150 runs)
HexToBytesJase: 15359.1 average ticks (over 150 runs)
HexToBytesJon is Jon's first version, and HexToBytesJon2 is the second variant.
HexToBytesJonCiC is Jon's version with CodesInChaos's suggested code.
HexToBytesJase is my attempt, based on both the above but with alternative nybble conversion which eschews error checking, and branching:
public static byte[] HexToBytesJase(string hexString)
{
if ((hexString.Length & 1) != 0)
{
throw new ArgumentException("Input must have even number of characters");
}
byte[] ret = new byte[hexString.Length/2];
for (int i = 0; i < ret.Length; i++)
{
int high = hexString[i*2];
int low = hexString[i*2+1];
high = (high & 0xf) + ((high & 0x40) >> 6) * 9;
low = (low & 0xf) + ((low & 0x40) >> 6) * 9;
ret[i] = (byte)((high << 4) | low);
}
return ret;
}
As a variant of Jon's if based ParseNybble:
public static byte[] ParseHex(string hexString)
{
if ((hexString.Length & 1) != 0)
{
throw new ArgumentException("Input must have even number of characters");
}
byte[] ret = new byte[hexString.Length / 2];
for (int i = 0; i < ret.Length; i++)
{
int high = ParseNybble(hexString[i*2]);
int low = ParseNybble(hexString[i*2+1]);
ret[i] = (byte) ((high << 4) | low);
}
return ret;
}
private static int ParseNybble(char c)
{
unchecked
{
uint i = (uint)(c - '0');
if(i < 10)
return (int)i;
i = ((uint)c & ~0x20u) - 'A';
if(i < 6)
return (int)i+10;
throw new ArgumentException("Invalid nybble: " + c);
}
}

Reduce lines of code with switch statement

I am teaching myself C# and one of the current chapters challenges asks me to prompt the user for a string, write back the string, count the number of characters, the instances of the letter 'e' and finally the instances of all vowels. It gave a hint to use switch but I couldn't figure out how to do it. I did get it to work by doing it manually, but I don't think that's the point. :) How could I use a switch statement to reduce the number of typed lines?
Console.WriteLine("Please type a sentence and hit enter: ");
string myString = Console.ReadLine();
int letterCount = myString.Split('e').Length - 1;
Console.Clear();
Console.WriteLine("Thank you. The sentence you entered was: \n\"{0}\"", myString);
Console.WriteLine("This sentence is {0} characters long.", myString.Length);
Console.WriteLine("It contains {0} instances of the letter \'e\'.", letterCount);
int vowelCount = 0;
int letterALower = myString.Split('a').Length - 1;
vowelCount += letterALower;
int letterELower = myString.Split('e').Length - 1;
vowelCount += letterELower;
int letterILower = myString.Split('i').Length - 1;
vowelCount += letterILower;
int letterOLower = myString.Split('o').Length - 1;
vowelCount += letterOLower;
int letterULower = myString.Split('u').Length - 1;
vowelCount += letterULower;
int letterAUpper = myString.Split('A').Length - 1;
vowelCount += letterAUpper;
int letterEUpper = myString.Split('E').Length - 1;
vowelCount += letterEUpper;
int letterIUpper = myString.Split('I').Length - 1;
vowelCount += letterIUpper;
int letterOUpper = myString.Split('O').Length - 1;
vowelCount += letterOUpper;
int letterUUpper = myString.Split('U').Length - 1;
vowelCount += letterUUpper;
Console.WriteLine("There are {0} vowels used.", vowelCount);
Console.ReadLine();
I know this isn't a good answer to the question, but I couldn't resist a one liner!
inputString.ToLower().Count(s=>"aeiou".Contains(s)); //count the vowels
Here's a simple solution:
string str = Console.ReadLine();
string low_str = str.ToLower();
Console.Clear();
Console.WriteLine("Thank you. The sentence you entered was: \n\"{0}\"", str);
Console.WriteLine("This sentence is {0} characters long.", str.Length);
int vowelCount = 0;
int eCount = 0;
for (int i = 0; i < low_str.Length; i++)
{
switch(low_str[i])
{
case 'e': eCount ++; vowelCount++; break;
case 'a': vowelCount++; break;
case 'o': vowelCount++; break;
case 'i': vowelCount++; break;
case 'u': vowelCount++; break;
case 'y': vowelCount++; break;
}
}
Console.WriteLine("It contains {0} instances of the letter \'e\'.", eCount);
Console.WriteLine("There are {0} vowels used.", vowelCount);
Console.ReadLine();
Notice that this could be done in an even fewer lines using this method (not the best way, but let's not go too deep into the framework details :) ):
int eCount = low_str.split(new char[]{'e'}) - 1;
int vowelCount = low_str.split(new char[]{'a','e','o','i','u','y'}) - 1;
Something like this (pseudo code, not actual C#)?
foreach (c in mySentence)
{
c = LowerCase(c);
switch (c) {
case 'a' :
case 'e' :
case 'i' :
case 'o' :
case 'u' :
nVowels ++;
break;
case ' ' :
case '\t' :
nBlanks++;
break;
default :
nChars++
break;
}
Here's a bit more info:
http://msdn.microsoft.com/en-us/library/06tc147t%28v=vs.80%29.aspx
I personally would do it with foreach and an array or vowels. This way it's easy to expand, like this:
Char[] vowels = {'e', 'a', 'o', 'i', 'u', 'y'};
string str = Console.ReadLine();
string low_str = str.ToLower();
Console.Clear();
Console.WriteLine("Thank you. The sentence you entered was: \n\"{0}\"", str);
Console.WriteLine("This sentence is {0} characters long.", str.Length);
int vowelCount = 0;
int eCount = 0;
foreach (char chara in low_str)
{
foreach (char vowel in vowels)
if (vowel == chara)
vowelCount++;
if (chara == 'e')
eCount++;
}
Console.WriteLine("It contains {0} instances of the letter \'e\'.", eCount);
Console.WriteLine("There are {0} vowels used.", vowelCount);
Console.ReadLine();

Categories

Resources