I'm working on a program that encodes and decodes letters to numbers. I have the Encoding properly built but the decoding is giving me problems. I'm using int to char conversions with the ASCII table as the key. It doesn't seem like the conversion logic for the decoding is right but I really have no idea how to fix it. This is my first time using this conversion method so I still don't fully understand it.
*edit This is on a windows form app that has three buttons and two text boxes. Encode is one button, and you type in a sentence and it outputs in in numbers for each letter. Decode is another but it does the opposite type in numbers and get words. the third button is clear so thats not important. Sorry I left this out of the initial question.
class LetterCodeLogic
{
public static string Encode(string msg)
{
string result = "";
string m = msg.ToUpper();
char c;
int x;
for(int i = 0; i < m.Length; i++)
{
c = Convert.ToChar(m[i]);
x = c;
if (x == 32)
{
x = 0;
}
else
{
x -= 64;
if (x < 1 || x > 26)
{
x = 99;
}
}
result += x.ToString() + " ";
}
return result;
}
public static string Decode(string msg)
{
string result = "";
string[] nums = msg.Split(',');
char c;
int x;
for (int i = 0; i < msg.Length; i++)
{
x = Convert.ToChar(msg[i]);
c = (char)x;
if (c == 0)
{
c = (char)32;
}
else
{
c -= (char)64;
if (c < 65 || c > 90)
{
c = (char)35;
}
}
result += c.ToString() + " ";
}
return result;
}
}
I find problems like this are far easier when you break them into parts. First, write functions that convert a single character to a number or vice versa.
static public byte Encode(char c)
{
if (c == ' ') return 0;
if (c >= 'A' && c <= 'Z') return (byte)(c - 'A' + 1);
return 99;
}
static public char Decode(byte n)
{
if (n == 0) return ' ';
if (n >= 1 && n <= 27) return (char)(n + 'A' - 1);
return '#';
}
Now the functions you need are very easy to write:
static public string Encode(string stringInput)
{
return string.Join(" ", stringInput.Select(Encode).Select( b => b.ToString() ));
}
static public string Decode(string numericInput)
{
return new string(numericInput.Split(' ').Select( n => byte.Parse(n)).Select(Decode).ToArray());
}
I actually tried to make a StringToASCII function from scratch in c#.
I get the input from _myString and this is the code :
public void convertToASCII() {
//A-Z --> 65-90
//a-z --> 97-122
//0-9 --> 48-57
//Space --> 32
int[] returnString = new int[_myString.Length];
int iTableau = 0;
char iAZ = 'A';
char iaz = 'a';
char i09 = '0';
char iSpace = ' ';
for(int i = 0; i < _myString.Length; i++)
{
if(_myString[i] >= 65 && _myString[i] <= 90 || _myString[i] >= 97 && _myString[i] <= 122 || _myString[i] >= 48 && _myString[i] <= 57 || _myString[i] == 32)
{
while(iAZ < 90 || iaz < 122 || iaz < 122 || i09 < 57 || _myString[i] == 32)
{
if(_myString[i] == iAZ && iAZ >= 'A' && iAZ <= 'Z')
{
returnString[iTableau] = iAZ;
iTableau++;
iAZ--;
}
else
{
iAZ++;
}
if(_myString[i] == iaz && iaz >= 'a' && iaz <= 'z')
{
returnString[iTableau] = iaz;
iTableau++;
iaz--;
}
else
{
iaz++;
}
if(_myString[i] == i09 && i09 >= '0' && i09 <= '9')
{
returnString[iTableau] = i09;
iTableau++;
i09--;
}
else
{
i09++;
}
if(_myString[i] == iSpace)
{
returnString[iTableau] = iSpace;
iTableau++;
}
}
}
}
_myString = "";
for (int i = 0; i < returnString.Length; i++)
{
_myString += returnString[i];
}
}
I also tried this kind of function which it works, but i would like to make one who checks only chars from A-Z and a-z and 0-9 and space.
Same thing as the first function, i take the input from a global string variable called "_myString".
public void convertToASCII()
{
string asciiChar;
string returnString = "";
foreach (char c in _myString)
{
asciiChar= ((int)(c)).ToString();
returnString += " " + asciiChar;
}
_myString = returnString;
}
This is actually relatively simple:
public string StringToLettersOrNumbersOrSpace(string input)
{
var sb = new StringBuilder();
for (int i = 0; i < input.Length; i++)
{
if (Char.IsLetterOrDigit(input[i]) || input[i] == ' ')
{
sb.Append(input[i]);
}
}
return sb.ToString();
}
First, you'll want to use StringBuilder instead of continuously appending to a string variable. Strings in C# are immutable, meaning that they can't be changed after they've been created, so doing something like string s1 = "aaa"; s1 += "bbb"; will actually create an entirely new string instead of just adding to the original. StringBuilder, on the other hand, is mutable, so you don't need to worry about reallocating a bunch of strings every time you want to concatenate strings (which gets progressively slower and slower as the string gets bigger).
Second, you can use Char.IsLetterOrDigit instead of using comparisons. The method takes a char as input and returns true if the character is a letter (uppercase or lowercase) or a number. This maps directly to your desired range a-z, A-Z, and 0-9. Since you also care about spaces, though, you will have to manually check for that.
I'm new to programming and C# and i'm trying to make Atbash Cipher in C#.
So I'm stuck at this problem: the cipher ran good, but they don't put spacing, or special characters (that not need to encode) in the result. I tried to make it but it got repeated.
So is there a way to let it skip the non-alphabet characters and put it on result ?
Here is my code
using System;
namespace AtbashCipher
{
class Program
{
static void Main()
{
Console.WriteLine("Atbash cipher v1.0");
Console.WriteLine();
Console.Write("Enter messages: ");
string userInput = Console.ReadLine();
Console.WriteLine();
string Alphabet = "abcdefghijklmnopqrstuvwxyz";
string AlphabetUpper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
string result = "";
Boolean SpecialChar = false;
foreach (char c in userInput)
{
for (int i = 0; i < Alphabet.Length; i++)
{
if (c == Alphabet[i])
{
result += Alphabet[Alphabet.Length - 1 - i];
}
if (c == AlphabetUpper[i])
{
result += AlphabetUpper[AlphabetUpper.Length - 1 - i];
}
}
}
//Print result for user
Console.WriteLine("Encoded messages: " + result);
Console.WriteLine();
Console.Write("Press any key to exit.");
Console.ReadKey();
}
}
}
I had the same task recently and here is my approach:
private string GetAtbash(string s)
{
var charArray = s.ToCharArray();
for (int i = 0; i < charArray.Length; i++)
{
char c = charArray[i];
if (c >= 'a' && c <= 'z')
{
charArray[i] = (char) (96 + (123 - c));
}
if (c >= 'A' && c <= 'Z')
{
charArray[i] = (char) (64 + (91 - c));
}
}
return new String(charArray);
}
You forgot to append the character if it's not between a-z or A-Z. You can check if (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') and simply append c to result if that's not the case.
I have the following code in Java:
public static byte[] hex(String hex) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int nexti = 0;
int nextb = 0;
boolean highoc = true;
outer:
while (true)
{
int number = -1;
while (number == -1) {
if (nexti == hex.length()) {
break outer;
}
char chr = hex.charAt(nexti);
if ((chr >= '0') && (chr <= '9'))
number = chr - '0';
else if ((chr >= 'a') && (chr <= 'f'))
number = chr - 'a' + 10;
else if ((chr >= 'A') && (chr <= 'F'))
number = chr - 'A' + 10;
else {
number = -1;
}
nexti++;
}
if (highoc) {
nextb = number << 4;
highoc = false;
} else {
nextb |= number;
highoc = true;
baos.write(nextb);
}
}
label161: return baos.toByteArray();
}
I'm trying to convert it to C#, and failing, because MemoryStream is the only option, and I don't have a buffer.
This is what I have now:
public static byte[] fromString(string hex)
{
MemoryStream baos = new MemoryStream();
int nexti = 0;
int nextb = 0;
bool highoc = true;
for (; ; )
{
int number = -1;
while (number == -1)
{
if (nexti == hex.Length)
{
goto END;
}
char chr = hex.ToCharArray()[nexti];
if (chr >= '0' && chr <= '9')
{
number = chr - '0';
}
else if (chr >= 'a' && chr <= 'f')
{
number = chr - 'a' + 10;
}
else if (chr >= 'A' && chr <= 'F')
{
number = chr - 'A' + 10;
}
else
{
number = -1;
}
nexti++;
}
if (highoc)
{
nextb = number << 4;
highoc = false;
}
else
{
nextb |= number;
highoc = true;
baos.Write(nextb);
}
}
END:
return baos.toByteArray();
}
What else can I do to make it work like the way in Java?.. Thanks.
Here is something similar
public static byte[] StringToByteArrayFastest(string hex) {
if (hex.Length % 2 == 1)
throw new Exception("The binary key cannot have an odd number of digits");
byte[] arr = new byte[hex.Length >> 1];
for (int i = 0; i < hex.Length >> 1; ++i)
{
arr[i] = (byte)((GetHexVal(hex[i << 1]) << 4) + (GetHexVal(hex[(i << 1) + 1])));
}
return arr;
}
public static int GetHexVal(char hex) {
int val = (int)hex;
//For uppercase A-F letters:
return val - (val < 58 ? 48 : 55);
//For lowercase a-f letters:
//return val - (val < 58 ? 48 : 87);
//Or the two combined, but a bit slower:
//return val - (val < 58 ? 48 : (val < 97 ? 55 : 87));
}
or
public static byte[] StringToByteArray(String hex)
{
int NumberChars = hex.Length;
byte[] bytes = new byte[NumberChars / 2];
for (int i = 0; i < NumberChars; i += 2)
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
return bytes;
}
or
private byte[] HexStringToByteArray(string hexString)
{
int hexStringLength = hexString.Length;
byte[] b = new byte[hexStringLength / 2];
for (int i = 0; i < hexStringLength; i += 2)
{
int topChar = (hexString[i] > 0x40 ? hexString[i] - 0x37 : hexString[i] - 0x30) << 4;
int bottomChar = hexString[i + 1] > 0x40 ? hexString[i + 1] - 0x37 : hexString[i + 1] - 0x30;
b[i / 2] = Convert.ToByte(topChar + bottomChar);
}
return b;
}
Here is alot more of them.
How do you convert Byte Array to Hexadecimal String, and vice versa?
I have written two functions that convert a string of whitespace-separated integers into an int array. The first function uses Substring and then applies System.Int32.Parse to convert the substring into an int value:
let intsOfString (s: string) =
let ints = ResizeArray()
let rec inside i j =
if j = s.Length then
ints.Add(s.Substring(i, j-i) |> System.Int32.Parse)
else
let c = s.[j]
if '0' <= c && c <= '9' then
inside i (j+1)
else
ints.Add(s.Substring(i, j-i) |> System.Int32.Parse)
outside (j+1)
and outside i =
if i < s.Length then
let c = s.[i]
if '0' <= c && c <= '9' then
inside i (i+1)
else
outside (i+1)
outside 0
ints.ToArray()
The second function traverses the characters of the string in-place accumulating the integer without creating a temporary substring:
let intsOfString (s: string) =
let ints = ResizeArray()
let rec inside n i =
if i = s.Length then
ints.Add n
else
let c = s.[i]
if '0' <= c && c <= '9' then
inside (10*n + int c - 48) (i+1)
else
ints.Add n
outside(i+1)
and outside i =
if i < s.Length then
let c = s.[i]
if '0' <= c && c <= '9' then
inside (int c - 48) (i+1)
else
outside (i+1)
outside 0
ints.ToArray()
Benchmarking on space-separated integers 1 to 1,000,000, the first version takes 1.5s whereas the second version takes 0.3s.
Parsing such values can be performance critical so leaving 5x performance on the table by using temporary substrings can be undesirable. Parsing integers is easy but parsing other values such as floating point numbers, decimals and dates is considerably harder.
So, are there built-in functions to parse directly from a substring within a string (i.e. using the given start and length of a string) in order to avoid generating a temporary string? If not, are there any libraries that provide efficient functions to do this?
System.Int32.Parse is slowlest, because it used CultureInfo, FormatInfo and etc; and performance reason is not in the temporary strings.
Code from reflection:
private unsafe static bool ParseNumber(ref char* str, NumberStyles options, ref Number.NumberBuffer number, NumberFormatInfo numfmt, bool parseDecimal)
{
number.scale = 0;
number.sign = false;
string text = null;
string text2 = null;
string str2 = null;
string str3 = null;
bool flag = false;
string str4;
string str5;
if ((options & NumberStyles.AllowCurrencySymbol) != NumberStyles.None)
{
text = numfmt.CurrencySymbol;
if (numfmt.ansiCurrencySymbol != null)
{
text2 = numfmt.ansiCurrencySymbol;
}
str2 = numfmt.NumberDecimalSeparator;
str3 = numfmt.NumberGroupSeparator;
str4 = numfmt.CurrencyDecimalSeparator;
str5 = numfmt.CurrencyGroupSeparator;
flag = true;
}
else
{
str4 = numfmt.NumberDecimalSeparator;
str5 = numfmt.NumberGroupSeparator;
}
int num = 0;
char* ptr = str;
char c = *ptr;
while (true)
{
if (!Number.IsWhite(c) || (options & NumberStyles.AllowLeadingWhite) == NumberStyles.None || ((num & 1) != 0 && ((num & 1) == 0 || ((num & 32) == 0 && numfmt.numberNegativePattern != 2))))
{
bool flag2;
char* ptr2;
if ((flag2 = (((options & NumberStyles.AllowLeadingSign) == NumberStyles.None) ? false : ((num & 1) == 0))) && (ptr2 = Number.MatchChars(ptr, numfmt.positiveSign)) != null)
{
num |= 1;
ptr = ptr2 - (IntPtr)2 / 2;
}
else
{
if (flag2 && (ptr2 = Number.MatchChars(ptr, numfmt.negativeSign)) != null)
{
num |= 1;
number.sign = true;
ptr = ptr2 - (IntPtr)2 / 2;
}
else
{
if (c == '(' && (options & NumberStyles.AllowParentheses) != NumberStyles.None && (num & 1) == 0)
{
num |= 3;
number.sign = true;
}
else
{
if ((text == null || (ptr2 = Number.MatchChars(ptr, text)) == null) && (text2 == null || (ptr2 = Number.MatchChars(ptr, text2)) == null))
{
break;
}
num |= 32;
text = null;
text2 = null;
ptr = ptr2 - (IntPtr)2 / 2;
}
}
}
}
c = *(ptr += (IntPtr)2 / 2);
}
int num2 = 0;
int num3 = 0;
while (true)
{
if ((c >= '0' && c <= '9') || ((options & NumberStyles.AllowHexSpecifier) != NumberStyles.None && ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))))
{
num |= 4;
if (c != '0' || (num & 8) != 0)
{
if (num2 < 50)
{
number.digits[(IntPtr)(num2++)] = c;
if (c != '0' || parseDecimal)
{
num3 = num2;
}
}
if ((num & 16) == 0)
{
number.scale++;
}
num |= 8;
}
else
{
if ((num & 16) != 0)
{
number.scale--;
}
}
}
else
{
char* ptr2;
if ((options & NumberStyles.AllowDecimalPoint) != NumberStyles.None && (num & 16) == 0 && ((ptr2 = Number.MatchChars(ptr, str4)) != null || (flag && (num & 32) == 0 && (ptr2 = Number.MatchChars(ptr, str2)) != null)))
{
num |= 16;
ptr = ptr2 - (IntPtr)2 / 2;
}
else
{
if ((options & NumberStyles.AllowThousands) == NumberStyles.None || (num & 4) == 0 || (num & 16) != 0 || ((ptr2 = Number.MatchChars(ptr, str5)) == null && (!flag || (num & 32) != 0 || (ptr2 = Number.MatchChars(ptr, str3)) == null)))
{
break;
}
ptr = ptr2 - (IntPtr)2 / 2;
}
}
c = *(ptr += (IntPtr)2 / 2);
}
bool flag3 = false;
number.precision = num3;
number.digits[(IntPtr)num3] = '\0';
if ((num & 4) != 0)
{
if ((c == 'E' || c == 'e') && (options & NumberStyles.AllowExponent) != NumberStyles.None)
{
char* ptr3 = ptr;
c = *(ptr += (IntPtr)2 / 2);
char* ptr2;
if ((ptr2 = Number.MatchChars(ptr, numfmt.positiveSign)) != null)
{
c = *(ptr = ptr2);
}
else
{
if ((ptr2 = Number.MatchChars(ptr, numfmt.negativeSign)) != null)
{
c = *(ptr = ptr2);
flag3 = true;
}
}
if (c >= '0' && c <= '9')
{
int num4 = 0;
do
{
num4 = num4 * 10 + (int)(c - '0');
c = *(ptr += (IntPtr)2 / 2);
if (num4 > 1000)
{
num4 = 9999;
while (c >= '0' && c <= '9')
{
c = *(ptr += (IntPtr)2 / 2);
}
}
}
while (c >= '0' && c <= '9');
if (flag3)
{
num4 = -num4;
}
number.scale += num4;
}
else
{
ptr = ptr3;
c = *ptr;
}
}
while (true)
{
if (!Number.IsWhite(c) || (options & NumberStyles.AllowTrailingWhite) == NumberStyles.None)
{
bool flag2;
char* ptr2;
if ((flag2 = (((options & NumberStyles.AllowTrailingSign) == NumberStyles.None) ? false : ((num & 1) == 0))) && (ptr2 = Number.MatchChars(ptr, numfmt.positiveSign)) != null)
{
num |= 1;
ptr = ptr2 - (IntPtr)2 / 2;
}
else
{
if (flag2 && (ptr2 = Number.MatchChars(ptr, numfmt.negativeSign)) != null)
{
num |= 1;
number.sign = true;
ptr = ptr2 - (IntPtr)2 / 2;
}
else
{
if (c == ')' && (num & 2) != 0)
{
num &= -3;
}
else
{
if ((text == null || (ptr2 = Number.MatchChars(ptr, text)) == null) && (text2 == null || (ptr2 = Number.MatchChars(ptr, text2)) == null))
{
break;
}
text = null;
text2 = null;
ptr = ptr2 - (IntPtr)2 / 2;
}
}
}
}
c = *(ptr += (IntPtr)2 / 2);
}
if ((num & 2) == 0)
{
if ((num & 8) == 0)
{
if (!parseDecimal)
{
number.scale = 0;
}
if ((num & 16) == 0)
{
number.sign = false;
}
}
str = ptr;
return true;
}
}
str = ptr;
return false;
}
public static int Parse(string s)
{
return Number.ParseInt32(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
}
internal unsafe static int ParseInt32(string s, NumberStyles style, NumberFormatInfo info)
{
byte* stackBuffer = stackalloc byte[1 * 114 / 1];
Number.NumberBuffer numberBuffer = new Number.NumberBuffer(stackBuffer);
int result = 0;
Number.StringToNumber(s, style, ref numberBuffer, info, false);
if ((style & NumberStyles.AllowHexSpecifier) != NumberStyles.None)
{
if (!Number.HexNumberToInt32(ref numberBuffer, ref result))
{
throw new OverflowException(Environment.GetResourceString("Overflow_Int32"));
}
}
else
{
if (!Number.NumberToInt32(ref numberBuffer, ref result))
{
throw new OverflowException(Environment.GetResourceString("Overflow_Int32"));
}
}
return result;
}
private unsafe static void StringToNumber(string str, NumberStyles options, ref Number.NumberBuffer number, NumberFormatInfo info, bool parseDecimal)
{
if (str == null)
{
throw new ArgumentNullException("String");
}
fixed (char* ptr = str)
{
char* ptr2 = ptr;
if (!Number.ParseNumber(ref ptr2, options, ref number, info, parseDecimal) || ((ptr2 - ptr / 2) / 2 < str.Length && !Number.TrailingZeros(str, (ptr2 - ptr / 2) / 2)))
{
throw new FormatException(Environment.GetResourceString("Format_InvalidString"));
}
}
}
I've written this one for doubles, that doesn't create a temporary substring. It's meant to be used inside a JSON parser so it limits itself to how doubles can be represented in JSON according to http://www.json.org/.
It's not optimal yet because it requires you to know where the number begins and ends (begin and end parameters), so you'll have to traverse the length of the number twice to find out where it ends. It's still around 10-15x faster than double.Parse and it could be fairly easily modified that it finds the end inside the function which is then returned as an out parameter to know where you have to resume parsing the main string.
Used like so:
Parsers.TryParseDoubleFastStream("1", 0, 1, out j);
Parsers.TryParseDoubleFastStream("2.0", 0, 3, out j);
Parsers.TryParseDoubleFastStream("3.5", 0, 3, out j);
Parsers.TryParseDoubleFastStream("-4.5", 0, 4, out j);
Parsers.TryParseDoubleFastStream("50.06", 0, 5, out j);
Parsers.TryParseDoubleFastStream("1000.65", 0, 7, out j);
Parsers.TryParseDoubleFastStream("-10000.8600", 0, 11, out j);
Code can be found here:
https://gist.github.com/3010984 (would be too lengthy to post here).
And StandardFunctions.IgnoreChar is for my purpose as simple as:
public static bool IgnoreChar(char c)
{
return c < 33;
}
Paste all this code into C# and call Test(). This is as close as you can get to operating directly on the string array to parse numbers using C#. It is built for speed, not elegance. The ParseInt and ParseFloat function were created for an OpenGL graphics engine to import vectors from text-based 3d models. Parsing floats is a significant bottleneck in that process. This was as fast as I could make it.
using System.Diagnostics;
private void Test()
{
Stopwatch sw = new Stopwatch();
StringBuilder sb = new StringBuilder();
int iterations = 1000;
// Build a string of 1000000 space separated numbers
for (var n = 0; n < iterations; n++)
{
if (n > 0)
sb.Append(' ');
sb.Append(n.ToString());
}
string numberString = sb.ToString();
// Time the process
sw.Start();
StringToInts(numberString, iterations);
//StringToFloats(numberString, iterations);
sw.Stop();
long proc1 = sw.ElapsedMilliseconds;
Console.WriteLine("iterations: {0} \t {1}ms", iterations, proc1);
}
private unsafe int[] StringToInts(string s, int length)
{
int[] ints = new int[length];
int index = 0;
int startpos = 0;
fixed (char* pStringBuffer = s)
{
fixed (int* pIntBuffer = ints)
{
for (int n = 0; n < s.Length; n++)
{
if (s[n] == ' ' || n == s.Length - 1)
{
if (n == s.Length - 1)
n++;
// pIntBuffer[index++] = int.Parse(new string(pStringBuffer, startpos, n - startpos));
pIntBuffer[index++] = ParseInt((pStringBuffer + startpos), n - startpos);
startpos = n + 1;
}
}
}
}
return ints;
}
private unsafe float[] StringToFloats(string s, int length)
{
float[] floats = new float[length];
int index = 0;
int startpos = 0;
fixed (char* pStringBuffer = s)
{
fixed (float* pFloatBuffer = floats)
{
for (int n = 0; n < s.Length; n++)
{
if (s[n] == ' ' || n == s.Length - 1)
{
if (n == s.Length - 1)
n++;
pFloatBuffer[index++] = ParseFloat((pStringBuffer + startpos), n - startpos); // int.Parse(new string(pStringBuffer, startpos, n - startpos));
startpos = n + 1;
}
}
}
}
return floats;
}
public static unsafe int ParseInt(char* input, int len)
{
int pos = 0; // read pointer position
int part = 0; // the current part (int, float and sci parts of the number)
bool neg = false; // true if part is a negative number
int* ret = stackalloc int[1];
while (pos < len && (*(input + pos) > '9' || *(input + pos) < '0') && *(input + pos) != '-')
pos++;
// sign
if (*(input + pos) == '-')
{
neg = true;
pos++;
}
// integer part
while (pos < len && !(input[pos] > '9' || input[pos] < '0'))
part = part * 10 + (input[pos++] - '0');
*ret = neg ? (part * -1) : part;
return *ret;
}
public static unsafe float ParseFloat(char* input, int len)
{
//float ret = 0f; // return value
int pos = 0; // read pointer position
int part = 0; // the current part (int, float and sci parts of the number)
bool neg = false; // true if part is a negative number
float* ret = stackalloc float[1];
// find start
while (pos < len && (input[pos] < '0' || input[pos] > '9') && input[pos] != '-' && input[pos] != '.')
pos++;
// sign
if (input[pos] == '-')
{
neg = true;
pos++;
}
// integer part
while (pos < len && !(input[pos] > '9' || input[pos] < '0'))
part = part * 10 + (input[pos++] - '0');
*ret = neg ? (float)(part * -1) : (float)part;
// float part
if (pos < len && input[pos] == '.')
{
pos++;
double mul = 1;
part = 0;
while (pos < len && !(input[pos] > '9' || input[pos] < '0'))
{
part = part * 10 + (input[pos] - '0');
mul *= 10;
pos++;
}
if (neg)
*ret -= (float)part / (float)mul;
else
*ret += (float)part / (float)mul;
}
// scientific part
if (pos < len && (input[pos] == 'e' || input[pos] == 'E'))
{
pos++;
neg = (input[pos] == '-'); pos++;
part = 0;
while (pos < len && !(input[pos] > '9' || input[pos] < '0'))
{
part = part * 10 + (input[pos++] - '0');
}
if (neg)
*ret /= (float)Math.Pow(10d, (double)part);
else
*ret *= (float)Math.Pow(10d, (double)part);
}
return (float)*ret;
}
So, are there built-in functions to parse directly from a substring within a string (i.e.
using the given start and length of a string) in order to avoid generating a temporary
string? If not, are there any libraries that provide efficient functions to do this?
It seems that you want to use a lexing buffer and a lexer, similar to what OCaml can provide with ocamllex and the Lexbuf buffer. (I cannot provide references for F#.)
If your benchmark involving a huge string of integers separated by other tokens is your typical case, it will work well. But in other situations, it could be impractical.
Not sure if this is any good, but have you tried something like:
var stringValues = input.split(" ");
var intValues = Array.ConvertAll(stringValues, s => int.Parse(s));