C# "Version-Updater" - c#

I want to increase the last number of the version (for Example: 1.0.0.0 -> 1.0.0.1).
I would prefer to kep this code :)
The actuall code looks like that:
private void UpdateApplicationVersion(string filepath)
{
string currentApplicationVersion = "1.2.3.4"
string newApplicationVersionDigit = ((currentApplicationVersion.Split('.')[3]) + 1).ToString();
string newApplicatonVersion = string.Empty;
for (int i = 0; i <= currentApplicationVersion.Length; i++)
{
if (i == 7)
{
newApplicatonVersion += newApplicationVersionDigit ;
}
else
{
newApplicatonVersion += currentApplicationVersion.ToCharArray()[i];
}
}

Do it simple way,
string v1 = "1.0.0.1";
string v2 = "1.0.0.4";
var version1 = new Version(v1);
var version2 = new Version(v2);
var result = version1.CompareTo(version2);
if (result > 0)
Console.WriteLine("version1 is greater");
else if (result < 0)
Console.WriteLine("version2 is greater");
else
Console.WriteLine("versions are equal");

I think it could be done by parsing all components of the version, manipulate the last one and put them together again as follows.
string[] Components = currentApplicationVersion.Split('.');
int Maj = Convert.ToInt32(Components[0]);
int Min = Convert.ToInt32(Components[1]);
int Revision = Convert.ToInt32(Components[2]);
int Build = Convert.ToInt32(Components[3]);
Build++;
string newApplicationVersion
= string.Format("{0}.{1}.{2}.{3}", Maj, Min, Revision, Build);

You can try Split and Join:
string currentApplicationVersion = "1.2.3.4";
int[] data = currentApplicationVersion.Split('.')
.Select(x => int.Parse(x, CultureInfo.InvariantCulture))
.ToArray();
// The last version component is data[data.Length - 1]
// so you can, say, increment it, e.g.
data[data.Length - 1] += 1;
// "1.2.3.5"
String result = String.Join(".", data);

There's a class build for working with version numbers. It's called Version and can be found in the System namespace
you can parse your current version by passing the string representing the version to the constructor
var currentApplicationVersion = new Version(currentApplicationVersionString);
and then get the new one with another of the constructors
var newApplicationVersion = new Version(
currentApplicationVersion.Major,
currentApplicationVersion.Minor,
currentApplicationVersion.Build,
currentApplicationVersion.Revision +1
);
and then simply call .ToString() if you need it as a string

Related

Building a new path-like string from an existing one

I'd like to modify a source string which is looking like
"one.two.three"
and transfer it into a string with slashes to use it as a folder string which has the following structure:
"one\one.two\one.two.three"
Do you know more elegant ways to realize this, than my solution below? I'm not very satisfied with my for-loops.
var folder = "one.two.three";
var folderParts = folder.Split('.');
var newFolder = new StringBuilder();
for (int i = 0; i < folderParts.Length; i++)
{
for (int j = 0; j < i; j++)
{
if (j == 0)
{
newFolder.Append("\\");
}
newFolder.Append($"{folderParts[j]}.");
}
newFolder.Append(folderParts[i]);
}
You can do this quite tersely with Regex
var newFolder = Regex.Replace(folder, #"\.", #"\$`.");
This matches on each period. Each time it finds a period, it inserts a backslash and then the entire input string before the match ($`). We have to add the period in again at the end.
So, steps are (< and > indicate text inserted by the substitution at that step):
Match on the 1st period. one<\one>.two.three
Match on the 2nd period. one\one.two<\one.two>.three
Result: one\one.two\one.two.three
For bonus points, use Path.DirectorySeparatorChar for cross-platform correctness.
var newFolder = Regex.Replace(folder, #"\.", $"{Path.DirectorySeparatorChar}$`.")
Here's another linqy way:
var a = "";
var newFolder = Path.Combine(folder.Split('.')
.Select(x => a += (a == "" ? "" : ".") + x).ToArray());
You can try Linq:
string folder = "one.two.three";
string[] parts = folder.Split('.');
string result = Path.Combine(Enumerable
.Range(1, parts.Length)
.Select(i => string.Join(".", parts.Take(i)))
.ToArray());
Console.Write(newFolder);
Outcome:
one\one.two\one.two.three
You can go forward-only in one loop like this:
var folder = "one.two.three";
var newFolder = new StringBuilder();
int index = -1;
while (index + 1 < folder.Length) {
index = folder.IndexOf('.', index + 1);
if (index < 0) {
newFolder.Append(folder);
break;
}
else {
newFolder.Append(folder, 0, index);
newFolder.Append(Path.DirectorySeparatorChar);
}
}
You can try it out here.
Instead of splitting the string first, I find it more elegant to start with what you have and reduce it:
var folder = "one.two.three";
var newFolder = string.Empty;
for (var f = folder; f.Any(); f = f.Remove(Math.Max(f.LastIndexOf('.'), 0)))
newFolder = Path.Combine(f, newFolder);
Console.WriteLine(newFolder);
Output:
one\one.two\one.two.three

Sum Up All characters of a string?

Idea is simple, user enters the number(string) in a textbox, for example 155321, the app would the sum 1+5+5+3+2+1, and give out the sum of them, since i am still learning, i don't know where to start. The app is made in WPF. Hope my explanation is clear.
Simple LINQ answer:
string s = // your input string
var result = s.Select(x => int.Parse(x.ToString())).Sum();
This is the universal answer, without a dependence of WPF.
I propose two solution :
1- standard :
string resultNumber = "12"; // your number
int sumNumber = 0;// result of calculating
for (int i = 0; i < resultNumber.Length; i++)
{
sumNumber = int.Parse(resultNumber.Substring(i, 1)) + sumNumber;
}
2- Recursive
public static int SumNumber(string number)
{
if(string.IsNullOrEmpty(number))
return 0;
else if(number.Length == 1)
return int.Parse(number);
else
return SumNumber(number.Substring(1)) + int.Parse(number.Substring(0, 1));
}
The cleanest solution is as follows:
var str = "19035683";
var sum = str.Sum(x => char.GetNumericValue(x));
Another similar solution is:
var str = "12312512341231";
var sum = str.Sum(x => x - '0');

How to get the intermediate portion of string?

I have a string as under
var input= "dbo.xyx.v1.UserDefinedFunction";
The desired output will be "xyx.v1";
My attempt is
var input = "dbo.xyx.v1.UserDefinedFunction";
var intermediate = input.Split('.').Skip(1);
var res = intermediate.Reverse().Skip(1).Aggregate((a, b) => b + "." + a);
works fine..but any other proper and elegant method?
Kindly note that it can be any part(in the example I just showed 4 parts)
e.g.
Input : "dbo.part1.part2.part3.part4.UserDefinedFunction"
Output : "part1.part2.part3.part4"
This returns always the mid part of a string which can be one or two parts(acc. to the total part-number).
var input = "dbo.xyx.v1.UserDefinedFunction";
string[] tokens = input.Split('.');
int midIndex = (tokens.Length - 1) / 2;
IEnumerable<int> midIndices = midIndex % 2 == 0
? new[] { midIndex }
: new[] { midIndex, midIndex + 1 };
string mid = string.Join(".", tokens.Where((t, i) => midIndices.Contains(i)));
Demo
So in this case it returns xyx.v1, for a string bo.xyx.v1 it returns v1 since that's the only mid-part.
string output= input.Substring(input.IndexOf('.') + 1,
input.LastIndexOf('.') - input.IndexOf('.') - 1);
var input = "dbo.xyx.v1.UserDefinedFunction";
var start = input.IndexOf('.');
var end = input.LastIndexOf('.');
string output;
if (start < end)
{
output = input.Substring(start+1, end-start-1);
}
else
{
output = input;
}
If you need to use LINQ, you can use Skip(1).Take(2) and string.Join, like this:
var parts = input.Split('.');
var res = string.Join(".", parts.Skip(1).Take(parts.Length-2));
If you need to throw away the first and the last parts, then you can use Substring, like this:
var start = input.IndexOf('.')+1;
var end = input.LastIndexOf('.')-1;
var res = input.Substring(start, end-start+1);
Finally, you can use regular expression, like this:
var res = Regex.Replace(input, "^[^.]+[.](.+)[.][^.]+$", "$1");
var input = "dbo.xyx.v1.UserDefinedFunction";
var res = string.Join(".", input.Split('.').Skip(1).Take(2));
You could simplify it and do:
var split = input.Split(".");
var result = String.Join(".", split[1], split[2]);
No need for Skip or Take.
var input = "dbo.xyx.v1.UserDefinedFunction";
var intermediate = input.Split('.');
var res = string.Join(".", intermediate[1],intermediate[2]);
EDIT: for any part version
var res = string.Join(".", intermediate.Skip(1).Take(intermediate.Length - 2));
[TestClass]
public class UnitTest2
{
[TestMethod]
public void TestMethod1()
{
var ret = "this.is.my.test.string".MySplit(".", new int[] {0,1,4 });//this.is.string
}
}
public static class Process {
public static string MySplit(this string Source, string seprator, int[] positionTokeep) {
var items = Source.Split(seprator.ToCharArray());
string ret = string.Empty;
for (int i = 0; i < positionTokeep.Length; i++) {
ret += items[positionTokeep[i]] + seprator;
}
if (!string.IsNullOrWhiteSpace(ret)) {
ret = ret.Substring(0,ret.Length - seprator.Length);
}
return ret;
}
}

Add separator to string at every N characters?

I have a string which contains binary digits. How to separate string after each 8 digit?
Suppose the string is:
string x = "111111110000000011111111000000001111111100000000";
I want to add a separator like ,(comma) after each 8 character.
output should be :
"11111111,00000000,11111111,00000000,11111111,00000000,"
Then I want to send it to a list<> last 8 char 1st then the previous 8 chars(excepting ,) and so on.
How can I do this?
Regex.Replace(myString, ".{8}", "$0,");
If you want an array of eight-character strings, then the following is probably easier:
Regex.Split(myString, "(?<=^(.{8})+)");
which will split the string only at points where a multiple of eight characters precede it.
Try this:
var s = "111111110000000011111111000000001111111100000000";
var list = Enumerable
.Range(0, s.Length/8)
.Select(i => s.Substring(i*8, 8));
var res = string.Join(",", list);
There's another Regex approach:
var str = "111111110000000011111111000000001111111100000000";
# for .NET 4
var res = String.Join(",",Regex.Matches(str, #"\d{8}").Cast<Match>());
# for .NET 3.5
var res = String.Join(",", Regex.Matches(str, #"\d{8}")
.OfType<Match>()
.Select(m => m.Value).ToArray());
...or old school:
public static List<string> splitter(string in, out string csv)
{
if (in.length % 8 != 0) throw new ArgumentException("in");
var lst = new List<string>(in/8);
for (int i=0; i < in.length / 8; i++) lst.Add(in.Substring(i*8,8));
csv = string.Join(",", lst); //This we want in input order (I believe)
lst.Reverse(); //As we want list in reverse order (I believe)
return lst;
}
Ugly but less garbage:
private string InsertStrings(string s, int insertEvery, char insert)
{
char[] ins = s.ToCharArray();
int length = s.Length + (s.Length / insertEvery);
if (ins.Length % insertEvery == 0)
{
length--;
}
var outs = new char[length];
long di = 0;
long si = 0;
while (si < s.Length - insertEvery)
{
Array.Copy(ins, si, outs, di, insertEvery);
si += insertEvery;
di += insertEvery;
outs[di] = insert;
di ++;
}
Array.Copy(ins, si, outs, di, ins.Length - si);
return new string(outs);
}
String overload:
private string InsertStrings(string s, int insertEvery, string insert)
{
char[] ins = s.ToCharArray();
char[] inserts = insert.ToCharArray();
int insertLength = inserts.Length;
int length = s.Length + (s.Length / insertEvery) * insert.Length;
if (ins.Length % insertEvery == 0)
{
length -= insert.Length;
}
var outs = new char[length];
long di = 0;
long si = 0;
while (si < s.Length - insertEvery)
{
Array.Copy(ins, si, outs, di, insertEvery);
si += insertEvery;
di += insertEvery;
Array.Copy(inserts, 0, outs, di, insertLength);
di += insertLength;
}
Array.Copy(ins, si, outs, di, ins.Length - si);
return new string(outs);
}
If I understand your last requirement correctly (it's not clear to me if you need the intermediate comma-delimited string or not), you could do this:
var enumerable = "111111110000000011111111000000001111111100000000".Batch(8).Reverse();
By utilizing morelinq.
Here my two little cents too. An implementation using StringBuilder:
public static string AddChunkSeparator (string str, int chunk_len, char separator)
{
if (str == null || str.Length < chunk_len) {
return str;
}
StringBuilder builder = new StringBuilder();
for (var index = 0; index < str.Length; index += chunk_len) {
builder.Append(str, index, chunk_len);
builder.Append(separator);
}
return builder.ToString();
}
You can call it like this:
string data = "111111110000000011111111000000001111111100000000";
string output = AddChunkSeparator(data, 8, ',');
One way using LINQ:
string data = "111111110000000011111111000000001111111100000000";
const int separateOnLength = 8;
string separated = new string(
data.Select((x,i) => i > 0 && i % separateOnLength == 0 ? new [] { ',', x } : new [] { x })
.SelectMany(x => x)
.ToArray()
);
I did it using Pattern & Matcher as following way:
fun addAnyCharacter(input: String, insertion: String, interval: Int): String {
val pattern = Pattern.compile("(.{$interval})", Pattern.DOTALL)
val matcher = pattern.matcher(input)
return matcher.replaceAll("$1$insertion")
}
Where:
input indicates Input string. Check results section.
insertion indicates Insert string between those characters. For example comma (,), start(*), hash(#).
interval indicates at which interval you want to add insertion character.
input indicates Input string. Check results section. Check results section; here I've added insertion at every 4th character.
Results:
I/P: 1234XXXXXXXX5678 O/P: 1234 XXXX XXXX 5678
I/P: 1234567812345678 O/P: 1234 5678 1234 5678
I/P: ABCDEFGHIJKLMNOP O/P: ABCD EFGH IJKL MNOP
Hope this helps.
As of .Net 6, you can simply use the IEnumerable.Chunk method (Which splits elements of a sequence into chunks) then reconcatenate the chunks using String.Join.
var text = "...";
string.Join(',', text.Chunk(size: 6).Select(x => new string(x)));
This is much faster without copying array (this version inserts space every 3 digits but you can adjust it to your needs)
public string GetString(double valueField)
{
char[] ins = valueField.ToString().ToCharArray();
int length = ins.Length + (ins.Length / 3);
if (ins.Length % 3 == 0)
{
length--;
}
char[] outs = new char[length];
int i = length - 1;
int j = ins.Length - 1;
int k = 0;
do
{
if (k == 3)
{
outs[i--] = ' ';
k = 0;
}
else
{
outs[i--] = ins[j--];
k++;
}
}
while (i >= 0);
return new string(outs);
}
For every 1 character, you could do this one-liner:
string.Join(".", "1234".ToArray()) //result: 1.2.3.4
If you intend to create your own function to acheive this without using regex or pattern matching methods, you can create a simple function like this:
String formatString(String key, String seperator, int afterEvery){
String formattedKey = "";
for(int i=0; i<key.length(); i++){
formattedKey += key.substring(i,i+1);
if((i+1)%afterEvery==0)
formattedKey += seperator;
}
if(formattedKey.endsWith("-"))
formattedKey = formattedKey.substring(0,formattedKey.length()-1);
return formattedKey;
}
Calling the mothod like this
formatString("ABCDEFGHIJKLMNOPQRST", "-", 4)
Would result in the return string as this
ABCD-EFGH-IJKL-MNOP-QRST
A little late to the party, but here's a simplified LINQ expression to break an input string x into groups of n separated by another string sep:
string sep = ",";
int n = 8;
string result = String.Join(sep, x.InSetsOf(n).Select(g => new String(g.ToArray())));
A quick rundown of what's happening here:
x is being treated as an IEnumerable<char>, which is where the InSetsOf extension method comes in.
InSetsOf(n) groups characters into an IEnumerable of IEnumerable -- each entry in the outer grouping contains an inner group of n characters.
Inside the Select method, each group of n characters is turned back into a string by using the String() constructor that takes an array of chars.
The result of Select is now an IEnumerable<string>, which is passed into String.Join to interleave the sep string, just like any other example.
I am more than late with my answer but you can use this one:
static string PutLineBreak(string str, int split)
{
for (int a = 1; a <= str.Length; a++)
{
if (a % split == 0)
str = str.Insert(a, "\n");
}
return str;
}

Reading and parsing integers from a text file

I'm trying to get a line of integers from a text file and parse them into separate variables. The text file is set up like this:
ID:HP:MP:STR:WIS:SPD:GOLD:XP
0:100:50:10:5:12:5:10
I want to split them with the : symbol in between each. One of the problems I'm having with this is being able to read the file line by line as strings, parsing them, and then storing the parsed strings as ints. Here is the code I'm attempting to use so far:
class monster
{
string line;
string[] mstats;
string[] mname;
char[] delimeterChars = {':'};
int id;
int i = -1;
int j = 0;
int hp;
int mp;
int str;
int wis;
int spd;
int gold;
int xp;
public monster(int id)
{
StreamReader stats = new StreamReader("monsterStats.txt");
while(i != id)
{
i++;
line = stats.ReadLine();
mstats = line.Split(delimeterChars);
j = 0;
foreach(string s in mstats)
{
if (j == 0) id = int.Parse(s);
else if (j == 1) hp = int.Parse(s);
else if (j == 2) mp = int.Parse(s);
else if (j == 3) str = int.Parse(s);
else if (j == 4) wis = int.Parse(s);
else if (j == 5) spd = int.Parse(s);
else if (j == 6) gold = int.Parse(s);
else if (j == 7) xp = int.Parse(s);
j++;
}
}
curHp = hp;
curMp = mp;
curSpd = spd;
curStr = str;
curWis = wis;
}
}
I get the following error when this code runs:
Input string was not in a correct format.
It references this part of the code:
if (j == 0) id = int.Parse(s);
Well, the first thing is to find out what the bad input was.
If you're expecting bad input data, use int.TryParse instead of just int.Parse. If you're not expecting bad input data, the fact that it's throwing an exception is probably appropriate - but you should examine your data to find out what's wrong.
I'd also recommend putting the parsing call once rather than in every case. It's not like you're doing a different kind of parsing for each field.
Why the foreach? How about:
id = int.Parse(mstats[0]);
hp = int.Parse(mstats[1]);
and so on. With a check beforehand that mstats is long enough.
A bit of Linq would let you get an array of integers in one shot:
int[] fields = line.Split(delimeterChars).Select(s => int.Parse(s)).ToArray();
id = field[0];
hp = field[2];
As for getting the code working, try printing out the line of text, and each piece of text just before you pass it to Parse. If it's not an integer, that's your problem.
A very good way for parsing text input are always regular expressions.
Regex r = new Regex(#"(?<id>\d+):(?<hp>\d+):(?<mp>\d+):(?<str>\d+):(?<wis>\d+):(?<spd>\d+):(?<gold>\d+):(?<xp>\d+)");
// loop over lines
Monster m = new Monster();
Match mc = r.Match(input);
m.hp = GetValue(mc.Groups["hp"], m.hp);
m.mp = GetValue(mc.Groups["mp"], m.mp);
m.str = GetValue(mc.Groups["str"], m.str);
...
// method to handle extracted value
private static int GetValue(Group g, int fallback)
{
if (g == null) throw new ArgumentNullException("g");
return g.Success ? Convert.ToInt32(g.Value) : fallback;
}
The method GetValue checks the extracted value. If the match failed (perhaps "" or "AB" instead of a number - g.Success is false) you can handle it the way you want. In my way i simply use an fallback value.
http://msdn.microsoft.com/en-us/library/hs600312.aspx

Categories

Resources