Retain 0 in front of a number - c#

I need help figuring out a logic.
I have a working code where the code will take a string and figure out every numbers in that string then add 1.
string str = "";
str = Console.ReadLine();
str = Regex.Replace(
str,
#"\d+",
m => (Double.Parse(m.Groups[0].Value) + 1).ToString()
);
Example:
If I enter "User 000079 is making $1000 from Jan 02 to Feb 24".
The code will produce output: "User 80 is making $1001 from Jan 3 to Feb 25".
The problem is, I want to keep the 0 in front of the 80 and 3. (i.e. User 000080 is making $1001 from Jan 03 to Feb 25)
How do I do that?
Additional Info: Let me clarify, this is just an example. What I want is just a way to add 1 to every number appearing in the string. So if it means UserID, January 31 - Yes, I still want them to increase by 1

This will do what you need:
string str = Console.ReadLine();
str = Regex.Replace(
str,
#"\d+",
m => (Double.Parse(m.Groups[0].Value) + 1).ToString().PadLeft(m.Groups[0].Value.Length, '0')
);

You can fix this with the ToString format like below:
String x = (50).ToString("D8"); // "00000050"
You can find more info about this here: msdn
edit: About the lengte if you do this the length will be correct:
System.Text.RegularExpressions.Regex.Replace(
str,
#"\d+",
m => (int.Parse(m.Groups[0].Value) + 1).ToString("D" + m.Groups[0].Value.Length)
);

It sounds like your user ID numbers aren't really 'numbers', but rather strings of numeric characters. Can the representation of the ID be changed to a string instead?
If you only care about the extra zeroes when rendering the ID, you can use String.Format to render the numeric value correctly using Custom Numeric Formats (specifically, see the 'Zero Placeholder' section).

Related

How to remove datetime from a Logfile string

I have a logfile like this:
[2016 01 10 11:10:44] Operation3 \r\n
[2016 01 10 11:10:40] Operation2 \r\n
[2016 01 10 11:10:36] Operation1 \r\n
on that I perform a readAlllines operation so that in a string I have:
[2016 01 10 11:10:44] Operation3 \r\n[2016 01 10 11:10:40] Operation2 \r\n[2016 01 10 11:10:36] Operation1 \r\n
Now I have to remove all those timestamps.
Being a newbie and to be on the safe side I'd split it and the search on each item for start=indexOf("[") and indexOf("]") and the remove the subString by cutting each and then join all of them.
I'd like to know a smarter way to do that.
--EDIT--
Ok for downvoting me I didn't considered everything.
additional constraints:
I can't be sure of the fact that all line have the timestamp so I have to check each line for a "[" starting and a "]" in the middle
I can't even be sure for the [XXXX] lenght since I could have [2016 1 1 11:1:4] instead than [2016 01 01 11:01:04]. So it's important to check for its lenght.
Thanks
You don't need to cut/paste the lines, you can use string.replace.
This takes into account the lenght of Environment.NewLine.
while(true)
{
int start;
if (lines.Substring(0,1) == "[")
start = 0;
else
start = lines.IndexOf(Environment.NewLine + "[") + Environment.NewLine.Length;
int end = lines.IndexOf("] ");
if (start == -1 || end == -1)
break;
string subString = lines.Substring(start, end + 2 - start);
lines = lines.Replace(subString, "");
}
ReadAllLines returns an array of lines, so you don't need to look for the start of each item. If your timestamp format will be consistent, you can just trim off the start of the string.
string[] lines = File.ReadAllLines("log.txt");
foreach (string line in lines)
{
string logContents = line.SubString("[XXXX XX XX XX:XX:XX] ".Length);
}
Or combine this with a linq Select to do it in one step
var logContentsWithoutTimestamps = File.ReadAllLines("log.txt")
.Select(x => x.SubString("[XXXX XX XX XX:XX:XX] ".Length);
Without consistent format, you will need to identify what you are looking for. I would write a regular expression to remove what you are looking for, otherwise you may get caught by things you weren't expecting (for example, you mention that some lines may not have timestamps - they might have something else in square brackets instead which you don't want to remove).
Example:
Regex rxTimeStamp = new Regex("^\[\d{4} \d{2} \d{2} \d{1,2}:\d{1,2}:\d{1,2}\]\s*");
string[] lines = File.ReadAllLines("log.txt");
foreach (string line in lines)
{
string logContents = rxTimeStamp.Replace(line, String.Empty);
}
// or
var logContentsWithoutTimestamps = File.ReadAllLines("log.txt")
.Select(x => rxTimeStamp.Replace(x, String.Empty));
You'll need to tune the regular expression based on whether it misses anything, but that's beyond the scope of this question.
Since your code works and you search for some different way:
string result = string.Join(string.Empty, str.Skip(22));
for each item
Explanation:
Since every timestamp is of equal length you don`t need to search for beginning or end. Normally you would have to do length checks (empty lines etc) but this works even for smaller strings - you will just get an empty string in return if the size is < 22. An alternative way if your file really just contains timestamps.

I'm trying to get the first two characters of my string to only output on the listbox

I'm trying to get the first two characters of my string to only output on the listbox,
string vin = "1GCHC24U83E614546";
string output = string.Format("{0} {1}",
(vin.Length - 16).ToString(),
(vin.Length - 15).ToString());
lsBox.Items.Add(output.ToString());
What am I doing wrong?
it outputs a "1 2" when I want "1 G"
Because vin contains 17 characters, vin.Length equals 17, and vin.Length - 16 equals 1, and vin.Length - 15 will be 2.
So, your code is equivalent to:
string output = string.Format("{0} {1}",
1.ToString(),
2.ToString());
That's why the string representations will be "1 2". Not "1 G". You will not get first two characters of your string on this process, you will get string representation of two integers with it.
You need to use String.Substring(Int32, Int32) overload like:
string vin = "1GCHC24U83E614546";
string output = vin.Substring(0, 2); // output will be "1G"
If you want to use them in a string.Format, simply you can do;
string output = string.Format("{0} {1}",
vin[0],
vin[1]); // output will be "1 G"
The following is probably less practical than Soner`s answer in your case, but may be useful to know about, e.g. if you want to play around with string.Format():
string vin = "1GCHC24U83E614546";
string output = string.Format("{0} {1}",
vin.First(), // Linq syntax to take first char
vin.Skip(1).First()); // take the second char

using concatenation on c#

What is the correct way to concatenate these elements?
Environment: C#-WinForm-Desktop.
In my app, I have a text file called config.ini. This file has values with this nomenclature:
csv_month_hour=value
The data are thus:
[csv]
csv_01_01=value // 24 hours a day in January
csv_01_02=value
csv_01_03=value
.
csv_02_01=value // 24 hours a day in February
csv_02_02=value
csv_02_03=value
.
// and so on
My app has this method called:
private void getMonthHour()
{
DateTime Xdt = DateTime.Now;
int Xmonth = Xdt.Month;
int Xhour = Xdt.Hour;
if (File.Exists("config.ini"))
{
IniFile ini = new IniFile("config.ini");
m3h = Convert.ToDouble(confg.csv["csv_" + Xmonth.ToString + "_" + Xhour.ToString]);
}
}
This method is called every seconds in timer_tick to check the month and time to use the corresponding value.
I need to know how to concatenate this:
m3h = Convert.ToDouble(confg.csv["csv_"+Xmonth.ToString+"_"+Xhour.ToString]);
An example of the code would be:
if (Xmonth==1&&Xhour==1){m3h = Convert.ToDouble(confg.csv.csv_01_01);}
else if (Xmonth==1&&Xhour==2){m3h = Convert.ToDouble(confg.csv.csv_01_02);}
else if (Xmonth==1&&Xhour==3){m3h = Convert.ToDouble(confg.csv.csv_01_03);}
// csv_month_hour in this case 01 is January.
else if (Xmonth==2&&Xhour==1){m3h = Convert.ToDouble(confg.csv.csv_02_01);}
// And so on, until December (12).
Putting aside the invalid syntax/compiler error from your method calls in your code, I suspect you're building the string but can't get the leading 0 in front of digits 0-9. So when Xmonth and Xhour are less than 10, your string is being built as "csv_1_1" instead of your intended "csv_01_01".
To instruct the ToString method to include a leading zero when needed, you can supply a custom numeric format string "00" (see the first entry in the link for "Zero placeholder").
Try using Xmonth.ToString("00") and Xhour.ToString("00"):
Monitor.malyt.m3h = Convert.ToDouble(confg.csv["csv_" +
Xmonth.ToString("00") + "_" +
Xhour.ToString("00")]);
This will output the values of Xmonth and Xhour with a single leading zero where needed.

Regex masking of words that contain a digit

Trying to come up with a 'simple' regex to mask bits of text that look like they might contain account numbers.
In plain English:
any word containing a digit (or a train of such words) should be matched
leave the last 4 digits intact
replace all previous part of the matched string with four X's (xxxx)
So far
I'm using the following:
[\-0-9 ]+(?<m1>[\-0-9]{4})
replacing with
xxxx${m1}
But this misses on the last few samples below
sample data:
123456789
a123b456
a1234b5678
a1234 b5678
111 22 3333
this is a a1234 b5678 test string
Actual results
xxxx6789
a123b456
a1234b5678
a1234 b5678
xxxx3333
this is a a1234 b5678 test string
Expected results
xxxx6789
xxxxb456
xxxx5678
xxxx5678
xxxx3333
this is a xxxx5678 test string
Is such an arrangement possible with a regex replace?
I think I"m going to need some greediness and lookahead functionality, but I have zero experience in those areas.
This works for your example:
var result = Regex.Replace(
input,
#"(?<!\b\w*\d\w*)(?<m1>\s?\b\w*\d\w*)+",
m => "xxxx" + m.Value.Substring(Math.Max(0, m.Value.Length - 4)));
If you have a value like 111 2233 33, it will print xxxx3 33. If you want this to be free from spaces, you could turn the lambda into a multi-line statement that removes whitespace from the value.
To explain the regex pattern a bit, it's got a negative lookbehind, so it makes sure that the word behind it does not have a digit in it (with optional word characters around the digit). Then it's got the m1 portion, which looks for words with digits in them. The last four characters of this are grabbed via some C# code after the regex pattern resolves the rest.
I don't think that regex is the best way to solve this problem and that's why I am posting this answer. For so complex situations, building the corresponding regex is too difficult and, what is worse, its clarity and adaptability is much lower than a longer-code approach.
The code below these lines delivers the exact functionality you are after, it is clear enough and can be easily extended.
string input = "this is a a1234 b5678 test string";
string output = "";
string[] temp = input.Trim().Split(' ');
bool previousNum = false;
string tempOutput = "";
foreach (string word in temp)
{
if (word.ToCharArray().Where(x => char.IsDigit(x)).Count() > 0)
{
previousNum = true;
tempOutput = tempOutput + word;
}
else
{
if (previousNum)
{
if (tempOutput.Length >= 4) tempOutput = "xxxx" + tempOutput.Substring(tempOutput.Length - 4, 4);
output = output + " " + tempOutput;
previousNum = false;
}
output = output + " " + word;
}
}
if (previousNum)
{
if (tempOutput.Length >= 4) tempOutput = "xxxx" + tempOutput.Substring(tempOutput.Length - 4, 4);
output = output + " " + tempOutput;
previousNum = false;
}
Have you tried this:
.*(?<m1>[\d]{4})(?<m2>.*)
with replacement
xxxx${m1}${m2}
This produces
xxxx6789
xxxx5678
xxxx5678
xxxx3333
xxxx5678 test string
You are not going to get 'a123b456' to match ... until 'b' becomes a number. ;-)
Here is my really quick attempt:
(\s|^)([a-z]*\d+[a-z,0-9]+\s)+
This will select all of those test cases. Now as for C# code, you'll need to check each match to see if there is a space at the beginning or end of the match sequence (e.g., the last example will have the space before and after selected)
here is the C# code to do the replace:
var redacted = Regex.Replace(record, #"(\s|^)([a-z]*\d+[a-z,0-9]+\s)+",
match => "xxxx" /*new String("x",match.Value.Length - 4)*/ +
match.Value.Substring(Math.Max(0, match.Value.Length - 4)));

Parse string with encapsulated int to an array that contains other numbers to be ignored

during my coding I've come across a problem that involved parsing a string like this:
{15} there are 194 red balloons, {26} there are 23 stickers, {40} there are 12 jacks, ....
my code involved pulling both the sentence and the number into two separate arrays.
I've solved the problem involving parsing out the sentence into its own array using a *.Remove(0, 5) to eliminate the first part the problem with that part was that I had to make sure that the file always was written to a standard where {##} where involved however it was not as elegant as I would like in that some times the number would be {3} and i would be forced to make it { 3}.
as there were also the chance of the string containing other numbers I wasn't able to simply parse out the integers first.
int?[] array = y.Split(',')
.Select(z =>
{
int value;
return int.TryParse(z, out value) ? value : (int?)null;
})
.ToArray();
so anyway back to the problem at hand, I need to be able to parse out "{##}" into an array with each having its own element.
Here's one way to do it using positive lookaheads/lookbehinds:
string s = "{15} there are 194 red balloons, {26} there are 23 stickers, {40} there are 12 jacks";
// Match all digits preceded by "{" and followed by "}"
int[] matches = Regex.Matches(s, #"(?<={)\d+(?=})")
.Cast<Match>()
.Select(m => int.Parse(m.Value))
.ToArray();
// Yields [15, 26, 40]

Categories

Resources