I want to know about how to splitting a value in string format in to two parts. Here in my asp application I'm parsing string value from view to controller.
And then I want to split the whole value in to two parts.
Example like: Most of the times value firest two letters could be TEXT value (like "PO" , "SS" , "GS" ) and the rest of the others are numbers (SS235452).
The length of the numbers cannot declare, since it generates randomly. So Want to split it from the begining of the string value. Need a help for that.
My current code is
string approvalnumber = approvalCheck.ApprovalNumber.ToUpper();
Thanks.
As you already mentioned that first part will have 2 letters and it's only second part which is varying, you can use Substring Method of String as shown below.
var textPart = input.Substring(0,2);
var numPart = input.Substring(2);
The first line fetches 2 characters from starting index zero and the second statement fetches all characters from index 2. You can cast the second part to a number if required.
Please note that the second parameter of Substring is not mentioned in second line. This parameter is for length and if nothing is mentioned it fetches till end of string.
You could try using regex to extract alpha, numbers from the string.
This javascript function returns only numbers from the input string.
function getNumbers(input) {
return input.match(/[0-9]+/g);
}
I'd use a RegExp. Considering the fact that you indicate ASP-NET-4 I assume you can't use tuples, out var etc. so it'd go as follows:
using System.Text.RegularExpressions;
using FluentAssertions;
using Xunit;
namespace Playground
{
public class Playground
{
public struct ProjectCodeMatch
{
public string Code { get; set; }
public int? Number { get; set; }
}
[Theory]
[InlineData("ABCDEFG123", "ABCDEFG", 123)]
[InlineData("123456", "", 123456)]
[InlineData("ABCDEFG", "ABCDEFG", null)]
[InlineData("ab123", "AB", 123)]
public void Split_Works(string input, string expectedCode, int? expectedNumber)
{
ProjectCodeMatch result;
var didParse = TryParse(input, out result);
didParse.Should().BeTrue();
result.Code.Should().Be(expectedCode);
result.Number.Should().Be(expectedNumber);
}
private static bool TryParse(string input, out ProjectCodeMatch result)
{
/*
* A word on this RegExp:
* ^ - the match must happen at the beginning of the string (nothing before that)
* (?<Code>[a-zA-Z]+) - grab any number of letters and name this part the "Code" group
* (?<Number>\d+) - grab any number of numbers and name this part the Number group
* {0,1} this group must occur at most 1 time
* $ - the match must end at the end of the string (nothing after that)
*/
var regex = new Regex(#"^(?<Code>[a-zA-Z]+){0,1}(?<Number>\d+){0,1}$");
var match = regex.Match(input);
if (!match.Success)
{
result = default;
return false;
}
int number;
var isNumber = int.TryParse(match.Groups["Number"].Value, out number);
result = new ProjectCodeMatch
{
Code = match.Groups["Code"].Value.ToUpper(),
Number = isNumber ? number : null
};
return true;
}
}
}
A linq answer:
string d = "PO1232131";
string.Join("",d.TakeWhile(a => Char.IsLetter(a)))
I don't understand where is my mistake, and would appreciate help. I would like to reverse the letter case in a string and return reversed chars to the List using List.Add() method.
using System.Linq;
using System.Collections.Generic;
using System;
public class Program
{
public static string ReverseCase(string str)
{
List<char> result = new List<char>();
foreach(char pew in str){
char.IsUpper(pew) ? result.Add(Char.ToLower(pew)):result.Add(Char.ToUpper(pew));
}
return result.ToString();
}
}
There are two issues here - first, the usage of the ? operator - you can't use code blocks there, just values. So instead of using it with two Add calls, you can use it to get the correct value within an Add call.
Second, calling ToString() on a List won't do what you expect it to do. You could, however, join the characters in the list to get a string:
public static string ReverseCase(string str)
{
List<char> result = new List<char>();
foreach(char pew in str){
result.Add(char.IsUpper(pew) ? Char.ToLower(pew) : Char.ToUpper(pew));
}
return String.Join("", result);
}
Get the char first and add it to the list, like this approach :
public static string ReverseCase(string str)
{
List<char> result = new List<char>();
foreach (char pew in str)
{
result.Add(char.IsUpper(pew) ? char.ToLower(pew) : char.ToUpper(pew));
}
return new string(result.ToArray());
}
Note that, result.ToString() can't convert list of char to string.
I hope you find this helpful.
I have a few examples of the first line of implementation of C functions that I need to extract the parameters from. For example:
double FuncName1(char *testnum, char *hipin_source, char *hipin_sense,
char *lopin_source, char *lopin_sense, DMM_ResRange range, float delay) {
and
double FuncName2(char *testnum, char *hipin, char *lopin, DMM_ResRange range, float delay, bool offset) {
Is there any RegEx that I can use in C# to extract function name, return type, but more importantly the arguments?
EDIT:
I am developing in C# and need to parse C-source code files creating objects like Func that has string Name, string ReturnType, List with Arg object having string argType, and string argName
EDIT 2:
Well, I finally tried and it is not working... may be I did not define those right... I am trying to parse a function call that either coded like this:
DCPS_Apply(1, // Module (optional comment)
5.0, // Voltage (optional comment)
2.0); // Current (optional comment)
or like this:
DCPS_Apply(1, 5.0, 2.0); // optional comment
and I need function name and the arguments...
Try following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string input =
#"double FuncName1(char *testnum, char *hipin_source, char *hipin_sense,
char *lopin_source, char *lopin_sense, DMM_ResRange range, float delay) { }
double FuncName2(char *testnum, char *hipin, char *lopin, DMM_ResRange range, float delay, bool offset) { }
";
string pattern1 = #"(?'type'\w+)\s+(?'name'[^(]+)\((?'parameters'[^)]+)\)";
string pattern2 = #"(?'key'[^\s]+)\s+(?'value'[*\w]+),?";
MatchCollection matches1 = Regex.Matches(input, pattern1);
foreach (Match match1 in matches1.Cast<Match>())
{
string parameters = match1.Groups["parameters"].Value;
MatchCollection matches2 = Regex.Matches(parameters, pattern2);
string[] key_value = matches2.Cast<Match>().Select((x, i) => string.Format("Key[{0}] : '{1}', Value[{0}] : '{2}'", i, x.Groups["key"].Value, x.Groups["value"].Value)).ToArray();
Console.WriteLine("Type : '{0}', Name : '{1}', Parameters : '{2}'", match1.Groups["type"].Value, match1.Groups["name"].Value, string.Join(";", key_value));
}
Console.ReadLine();
}
}
}
I'm essentially trying to read an xml file. One of the values has a suffix, e.g. "30d". This is meant to mean '30 days'. So I'm trying to convert this to a DateTime.Now.AddDays(30). To read this field in the XML, i decided to use an Enum:
enum DurationType { Min = "m", Hours = "h", Days = "d" }
Now I'm not exactly sure how exactly to approach this efficiently (I'm a little daft when it comes to enums). Should I separate the suffix, in this case "d", out of the string first, then try and match it in the enum using a switch statement?
I guess if you dumb down my question, it'd be: What's the best way to get from 30d, to DateTime.Now.AddDays(30) ?
You could make an ExtensionMethod to parse the string and return the DateTime you want
Something like:
public static DateTime AddDuration(this DateTime datetime, string str)
{
int value = 0;
int mutiplier = str.EndsWith("d") ? 1440 : str.EndsWith("h") ? 60 : 1;
if (int.TryParse(str.TrimEnd(new char[]{'m','h','d'}), out value))
{
return datetime.AddMinutes(value * mutiplier);
}
return datetime;
}
Usage:
var date = DateTime.Now.AddDuration("2d");
This seems like a good place to use regular expressions; specifically, capture groups.
Below is a working example:
using System;
using System.Text.RegularExpressions;
namespace RegexCaptureGroups
{
class Program
{
// Below is a breakdown of this regular expression:
// First, one or more digits followed by "d" or "D" to represent days.
// Second, one or more digits followed by "h" or "H" to represent hours.
// Third, one or more digits followed by "m" or "M" to represent minutes.
// Each component can be separated by any number of spaces, or none.
private static readonly Regex DurationRegex = new Regex(#"((?<Days>\d+)d)?\s*((?<Hours>\d+)h)?\s*((?<Minutes>\d+)m)?", RegexOptions.IgnoreCase);
public static TimeSpan ParseDuration(string input)
{
var match = DurationRegex.Match(input);
var days = match.Groups["Days"].Value;
var hours = match.Groups["Hours"].Value;
var minutes = match.Groups["Minutes"].Value;
int daysAsInt32, hoursAsInt32, minutesAsInt32;
if (!int.TryParse(days, out daysAsInt32))
daysAsInt32 = 0;
if (!int.TryParse(hours, out hoursAsInt32))
hoursAsInt32 = 0;
if (!int.TryParse(minutes, out minutesAsInt32))
minutesAsInt32 = 0;
return new TimeSpan(daysAsInt32, hoursAsInt32, minutesAsInt32, 0);
}
static void Main(string[] args)
{
Console.WriteLine(ParseDuration("30d"));
Console.WriteLine(ParseDuration("12h"));
Console.WriteLine(ParseDuration("20m"));
Console.WriteLine(ParseDuration("1d 12h"));
Console.WriteLine(ParseDuration("5d 30m"));
Console.WriteLine(ParseDuration("1d 12h 20m"));
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
}
EDIT: Below is an alternative, slightly more condensed version of the above, though I'm not sure which one I prefer more. I'm usually not a fan of overly dense code.
I adjusted the regular expression to put a limit of 10 digits on each number. This allows me to safely use the int.Parse function, because I know that the input consists of at least one digit and at most ten (unless it didn't capture at all, in which case it would be empty string: hence, the purpose of the ParseInt32ZeroIfNullOrEmpty method).
// Below is a breakdown of this regular expression:
// First, one to ten digits followed by "d" or "D" to represent days.
// Second, one to ten digits followed by "h" or "H" to represent hours.
// Third, one to ten digits followed by "m" or "M" to represent minutes.
// Each component can be separated by any number of spaces, or none.
private static readonly Regex DurationRegex = new Regex(#"((?<Days>\d{1,10})d)?\s*((?<Hours>\d{1,10})h)?\s*((?<Minutes>\d{1,10})m)?", RegexOptions.IgnoreCase);
private static int ParseInt32ZeroIfNullOrEmpty(string input)
{
return string.IsNullOrEmpty(input) ? 0 : int.Parse(input);
}
public static TimeSpan ParseDuration(string input)
{
var match = DurationRegex.Match(input);
return new TimeSpan(
ParseInt32ZeroIfNullOrEmpty(match.Groups["Days"].Value),
ParseInt32ZeroIfNullOrEmpty(match.Groups["Hours"].Value),
ParseInt32ZeroIfNullOrEmpty(match.Groups["Minutes"].Value),
0);
}
EDIT: Just to take this one more step, I've added another version below, which handles days, hours, minutes, seconds, and milliseconds, with a variety of abbreviations for each. I split the regular expression into multiple lines for readability. Note, I also had to adjust the expression by using (\b|(?=[^a-z])) at the end of each component: this is because the "ms" unit was being captured as the "m" unit. The special syntax of "?=" used with "[^a-z]" indicates to match the character but not to "consume" it.
// Below is a breakdown of this regular expression:
// First, one to ten digits followed by "d", "dy", "dys", "day", or "days".
// Second, one to ten digits followed by "h", "hr", "hrs", "hour", or "hours".
// Third, one to ten digits followed by "m", "min", "minute", or "minutes".
// Fourth, one to ten digits followed by "s", "sec", "second", or "seconds".
// Fifth, one to ten digits followed by "ms", "msec", "millisec", "millisecond", or "milliseconds".
// Each component may be separated by any number of spaces, or none.
// The expression is case-insensitive.
private static readonly Regex DurationRegex = new Regex(#"
((?<Days>\d{1,10})(d|dy|dys|day|days)(\b|(?=[^a-z])))?\s*
((?<Hours>\d{1,10})(h|hr|hrs|hour|hours)(\b|(?=[^a-z])))?\s*
((?<Minutes>\d{1,10})(m|min|minute|minutes)(\b|(?=[^a-z])))?\s*
((?<Seconds>\d{1,10})(s|sec|second|seconds)(\b|(?=[^a-z])))?\s*
((?<Milliseconds>\d{1,10})(ms|msec|millisec|millisecond|milliseconds)(\b|(?=[^a-z])))?",
RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
private static int ParseInt32ZeroIfNullOrEmpty(string input)
{
return string.IsNullOrEmpty(input) ? 0 : int.Parse(input);
}
public static TimeSpan ParseDuration(string input)
{
var match = DurationRegex.Match(input);
return new TimeSpan(
ParseInt32ZeroIfNullOrEmpty(match.Groups["Days"].Value),
ParseInt32ZeroIfNullOrEmpty(match.Groups["Hours"].Value),
ParseInt32ZeroIfNullOrEmpty(match.Groups["Minutes"].Value),
ParseInt32ZeroIfNullOrEmpty(match.Groups["Seconds"].Value),
ParseInt32ZeroIfNullOrEmpty(match.Groups["Milliseconds"].Value));
}
update:
Don't vote for this. I'm leaving it simply because it's an alternative approach. Instead look at sa_ddam213 and Dr. Wily's Apprentice's answers.
Should I separate the suffix, in this case "d", out of the string
first, then try and match it in the enum using a switch statement?
Yes.
For a fully working example:
private void button1_Click( object sender, EventArgs e ) {
String value = "30d";
Duration d = (Duration)Enum.Parse(typeof(Duration), value.Substring(value.Length - 1, 1).ToUpper());
DateTime result = d.From(new DateTime(), value);
MessageBox.Show(result.ToString());
}
enum Duration { D, W, M, Y };
static class DurationExtensions {
public static DateTime From( this Duration duration, DateTime dateTime, Int32 period ) {
switch (duration)
{
case Duration.D: return dateTime.AddDays(period);
case Duration.W: return dateTime.AddDays((period*7));
case Duration.M: return dateTime.AddMonths(period);
case Duration.Y: return dateTime.AddYears(period);
default: throw new ArgumentOutOfRangeException("duration");
}
}
public static DateTime From( this Duration duration, DateTime dateTime, String fullValue ) {
Int32 period = Convert.ToInt32(fullValue.ToUpper().Replace(duration.ToString(), String.Empty));
return From(duration, dateTime, period);
}
}
I really don't see how using an enum helps here.
Here's how I might approach it.
string s = "30d";
int typeIndex = s.IndexOfAny(new char[] { 'd', 'w', 'm' });
if (typeIndex > 0)
{
int value = int.Parse(s.Substring(0, typeIndex));
switch (s[typeIndex])
{
case 'd':
result = DateTime.Now.AddDays(value);
break;
case 'w':
result = DateTime.Now.AddDays(value * 7);
break;
case 'm':
result = DateTime.Now.AddMonths(value);
break;
}
}
Depending on the reliability of your input data, you might need to use int.TryParse() instead of int.Parse(). Otherwise, this should be all you need.
Note: I've also written a sscanf() replacement for .NET that would handle this quite easily. You can see the code for that in the article A sscanf() Replacement for .NET.
Try the following code, assuming that values like "30d" are in a string 'val'.
DateTime ConvertValue(string val) {
if (val.Length > 0) {
int prefix = Convert.ToInt32(val.Length.Remove(val.Length-1));
switch (val[val.Length-1]) {
case 'd': return DateTime.Now.AddDays(prefix);
case 'm': return DateTime.Now.AddMonths(prefix);
// etc.
}
throw new ArgumentException("string in unexpected format.");
}
Example of a console application example/tutorial:
enum DurationType
{
[DisplayName("m")]
Min = 1,
[DisplayName("h")]
Hours = 1 * 60,
[DisplayName("d")]
Days = 1 * 60 * 24
}
internal class Program
{
private static void Main(string[] args)
{
string input1 = "10h";
string input2 = "1d10h3m";
var x = GetOffsetFromDate(DateTime.Now, input1);
var y = GetOffsetFromDate(DateTime.Now, input2);
}
private static Dictionary<string, DurationType> suffixDictionary
{
get
{
return Enum
.GetValues(typeof (DurationType))
.Cast<DurationType>()
.ToDictionary(duration => duration.GetDisplayName(), duration => duration);
}
}
public static DateTime GetOffsetFromDate(DateTime date, string input)
{
MatchCollection matches = Regex.Matches(input, #"(\d+)([a-zA-Z]+)");
foreach (Match match in matches)
{
int numberPart = Int32.Parse(match.Groups[1].Value);
string suffix = match.Groups[2].Value;
date = date.AddMinutes((int)suffixDictionary[suffix]);
}
return date;
}
}
[AttributeUsage(AttributeTargets.Field)]
public class DisplayNameAttribute : Attribute
{
public DisplayNameAttribute(String name)
{
this.name = name;
}
protected String name;
public String Name { get { return this.name; } }
}
public static class ExtensionClass
{
public static string GetDisplayName<TValue>(this TValue value) where TValue : struct, IConvertible
{
FieldInfo fi = typeof(TValue).GetField(value.ToString());
DisplayNameAttribute attribute = (DisplayNameAttribute)fi.GetCustomAttributes(typeof(DisplayNameAttribute), false).FirstOrDefault();
if (attribute != null)
return attribute.Name;
return value.ToString();
}
}
Uses an attribute to define your suffix, uses the enum value to define your offset.
Requires:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
It may be considered a hack to use the enum integer value but this example will still let you parse out all the Enums (for any other use like switch case) with little tweaks.
Enums can't be backed with non-numeric types, so string-based enums are out. It's possible you may be overthinking it. Without knowing any more about the problem, the most straightforward solution seems to be splitting off the last character, converting the rest to an int, and then handling each final char as a separate case.
I'd suggest using regexp to strip the number first and than execute Enum.Parse Method to evaluate the value of the enum. Than you can use a switch (see Corylulu's answer) to get the right offset, based on the parsed number and enum value.
I would to know, Is there any method in StringBuilder class in C#, which can remove string characters without changing other character of same value within different index?
Like for a string like "5002", what if want to remove character in first index to "3"?
I'm using StringBuilder's remove method for the specified string and it's returning me an output as "5332" instead of "5302"?
The code which I'm using to accomplish my requirement is:
StringBuilder j = new StringBuilder("5002");
Console.WriteLine(j.Replace(j.ToString(1, 1),"3");
Well, you can use the indexer:
builder[1] = '3';
Is that what you're after?
For example:
using System;
using System.Text;
class Test
{
static void Main()
{
StringBuilder builder = new StringBuilder("5002");
builder[1] = '3';
Console.WriteLine(builder); // Prints 5302
}
}