I receive series of strings followed by non-negative numbers, e.g. "a3". I have to print on the console each string repeated N times (uppercase) where N is a number in the input. In the example, the result: "AAA". As you see, I have tried to get the numbers from the input and I think it's working fine. Can you help me with the repeating?
string input = Console.ReadLine();
//input = "aSd2&5s#1"
MatchCollection matched = Regex.Matches(input, #"\d+");
List<int> repeatsCount = new List<int>();
foreach (Match match in matched)
{
int repeatCount = int.Parse(match.Value);
repeatsCount.Add(repeatCount);
}
//repeatsCount: [2, 5, 1]
//expected output: ASDASD&&&&&S# ("aSd" is converted to "ASD" and repeated twice;
// "&" is repeated 5 times; "s#" is converted to "S#" and repeated once.)
For example, if we have "aSd2&5s#1":
"aSd" is converted to "ASD" and repeated twice; "&" is repeated 5 times; "s#" is converted to "S#" and repeated once.
Let the pattern include two groups: value to repeat and how many times to repeat:
#"(?<value>[^0-9]+)(?<times>[0-9]+)"
Then we can operate with these groups, say, with a help of Linq:
string source = "aSd2&5s#1";
string result = string.Concat(Regex
.Matches(source, #"(?<value>[^0-9]+)(?<times>[0-9]+)")
.OfType<Match>()
.SelectMany(match => Enumerable // for each match
.Repeat(match.Groups["value"].Value.ToUpper(), // repeat "value"
int.Parse(match.Groups["times"].Value)))); // "times" times
Console.Write(result);
Outcome:
ASDASD&&&&&S#
Edit: Same idea without Linq:
StringBuilder sb = new StringBuilder();
foreach (Match match in Regex.Matches(source, #"(?<value>[^0-9]+)(?<times>[0-9]+)")) {
string value = match.Groups["value"].Value.ToUpper();
int times = int.Parse(match.Groups["times"].Value);
for (int i = 0; i < times; ++i)
sb.Append(value);
}
string result = sb.ToString();
You can extract substring and how often it should be repeated with this regex:
(?<content>.+?)(?<count>\d+)
Now you can use a StringBuilder to create output string. Full code:
var input = "aSd2&5s#1";
var regex = new Regex("(?<content>.+?)(?<count>\\d+)");
var matches = regex.Matches(input).Cast<Match>();
var sb = new StringBuilder();
foreach (var match in matches)
{
var count = int.Parse(match.Groups["count"].Value);
for (var i = 0; i < count; ++i)
sb.Append(match.Groups["content"].Value.ToUpper());
}
Console.WriteLine(sb.ToString());
Output is
ASDASD&&&&&S#
Another solution without LINQ
i tried to keep the solution so it would be similar to yours
string input = "aSd2&5s#1";
var matched = Regex.Matches(input, #"\d+");
var builder = new StringBuilder();
foreach (Match match in matched)
{
string stingToDuplicate = input.Split(Char.Parse(match.Value))[0];
input = input.Replace(stingToDuplicate, String.Empty).Replace(match.Value, String.Empty);
for (int i = 0; i < Convert.ToInt32(match.Value); i++)
{
builder.Append(stingToDuplicate.ToUpper());
}
}
and finally Console.WriteLine(builder.ToString());
which result ASDASD&&&&&S#
My solution is same as others with slight differences :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace ConsoleApplication107
{
class Program
{
static void Main(string[] args)
{
string input = "aSd2&5s#1";
string pattern1 = #"[a-zA-z#&]+\d+";
MatchCollection matches = Regex.Matches(input, pattern1);
string output = "";
foreach(Match match in matches.Cast<Match>().ToList())
{
string pattern2 = #"(?'string'[^\d]+)(?'number'\d+)";
Match match2 = Regex.Match(match.Value, pattern2);
int number = int.Parse(match2.Groups["number"].Value);
string str = match2.Groups["string"].Value;
output += string.Join("",Enumerable.Repeat(str.ToUpper(), number));
}
Console.WriteLine(output);
Console.ReadLine();
}
}
}
Very simple program. No linq nothing, simple string and for loop.
string input = "aSd2&5s#1";
char[] inputArray = input.ToCharArray();
string output = "";
string ab = "";
foreach (char c in inputArray)
{
int x;
string y;
if(int.TryParse(c.ToString(), out x))
{
string sb = "";
ab = ab.ToUpper();
for(int i=0;i<b;i++)
{
sb += ab;
}
ab = "";
output += sb;
}
else
{
ab += c;
}
}
if(!string.IsNullOrEmpty(ab))
{
output += ab.ToUpper();
}
Console.WriteLine(output);
Hope it helps.
Related
This question already has answers here:
how can i split a string by multiple delimiters and keep the delimiters?
(1 answer)
RegEx - Match Numbers of Variable Length
(4 answers)
Closed 4 years ago.
I have a text file. One of the columns contains a field which contains text along with numbers.
I'm trying to figure out the best way to split the numbers and text.
Below is an example of the typical values in the field.
.2700 Aqr sh./Tgt sh.
USD 2.4700/Tgt sh.
Currently I'm making use of the Split function (code below) however feel there is probably a smarter way of doing this.
My assumption is there will only ever be one number in the text (I'm 99% sure this is the case) however I have only seen a few examples so its possible my code below will not work.
I have read a little on regex. But not sure I tested it properly as it didn't quite get the output I wanted. For example
string input = "USD 2.4700/Tgt sh.";
string[] numbers = Regex.Split(input, #"\D+");
foreach (string value in numbers)
{
if (!string.IsNullOrEmpty(value))
{
int i = int.Parse(value);
Console.WriteLine("Number: {0}", i);
}
}
But the output is,
2
47
Whereas I was expecting 2.47 and I also don't want to lose the text. My desired result is
myText = "USD Tgt sh."
myNum = 2.47
For the other example
myText = "Aqr sh./Tgt sh."
myNum = 0.27
My Code
string[] sData = sTerms.Split(' ');
double num;
bool isNum = double.TryParse(sData[0], out num);
if(isNum)
{
ma.StockTermsNum = num;
StringBuilder sb = new StringBuilder();
for (int i = 1; i < sData.Length; i++)
sb = sb.Append(sData[i] + " ");
ma.StockTerms = sb.ToString();
}
else
{
string[] sNSplit = sData[1].Split('/');
ma.StockTermsNum = Convert.ToDouble(sNSplit[0]);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < sData.Length; i++)
{
if (i == 1)
sb = sb.Append(sNSplit[i] + " ");
else
sb = sb.Append(sData[i] + " ");
}
ma.StockTerms = sb.ToString();
}
I suggest spliting by group, (...) in order to preserve delimiter:
string source = #".2700 Aqr sh./Tgt sh.";
//string source = "USD 2.4700/Tgt sh.";
// please, notice "(...)" in the pattern - group
string[] parts = Regex.Split(source, #"([0-9]*\.?[0-9]+)");
// combining all texts
string myText = string.Concat(parts.Where((v, i) => i % 2 == 0));
// combining all numbers
string myNumber = string.Concat(parts.Where((v, i) => i % 2 != 0));
Tests:
string[] tests = new string[] {
#".2700 Aqr sh./Tgt sh.",
#"USD 2.4700/Tgt sh.",
};
var result = tests
.Select(test => new {
text = test,
parts = Regex.Split(test, #"([0-9]*\.?[0-9]+)"),
})
.Select(item => new {
text = item.text,
myText = string.Concat(item.parts.Where((v, i) => i % 2 == 0)),
myNumber = string.Concat(item.parts.Where((v, i) => i % 2 != 0)),
})
.Select(item => $"{item.text,-25} : {item.myNumber,-15} : {item.myText}");
Console.WriteLine(string.Join(Environment.NewLine, result));
Outcome:
.2700 Aqr sh./Tgt sh. : Aqr sh./Tgt sh. : .2700
USD 2.4700/Tgt sh. : USD /Tgt sh. : 2.4700
Could by something like this regex:
string input = "USD 2.4700/Tgt sh.";
var numbers = Regex.Matches(input, #"[\d]+\.?[\d]*");
foreach (Match res in numbers)
{
if (!string.IsNullOrEmpty(res.Value))
{
decimal i = decimal.Parse(res.Value);
Console.WriteLine("Number: {0}", i);
}
}
I would suggest you to use System.Text.RegularExpressions.RegEx. Here is example how you can achieve it:
static void Main(string[] args)
{
string a1 = ".2700 Aqr sh./Tgt sh.";
string a2 = "USD 2.4700/Tgt sh.";
var firstStringNums = GetNumbersFromString(ref a1);
Console.Write("My Text: {0}",a1);
Console.Write("myNums: ");
foreach(double a in firstStringNums)
{
Console.Write(a +"\t");
}
var secondStringNums = GetNumbersFromString(ref a2);
Console.Write("My Text: {0}", a2);
Console.Write("myNums: ");
foreach (double a in secondStringNums)
{
Console.Write(a + "\t");
}
}
public static List<double> GetNumbersFromString(ref string input)
{
List<double> result = new List<double>();
Regex r = new Regex("[0-9.,]+");
var numsFromString = r.Matches(input);
foreach(Match a in numsFromString)
{
if(double.TryParse(a.Value,out double val))
{
result.Add(val);
input =input.Replace(a.Value, "");
}
}
return result;
}
The pattern is just an example and off course will not cover every case that you will imagine.
i have following problem: I have text like this (more than 200 lines):
dsadsadsads(-123|12)sdakodskoakosdakodsadsayxvmyxcmxcym,§§¨§¨§(-43|23)sdadasdas
I want get numbers from text like this:
-123|12
-43|23
Numbers are always in ( ).
What is the fast way, how to get this number. Is possible use some regex? How?
Or brute force foor loop?
Thank you for your reply.
You can use Regex for this purpose.
string str = "dsadsadsads(-123|12)sdakodskoakosdakodsadsayxvmyxcmxcym,§§¨§¨§(-43|23)sdadasdas";
var matches = Regex.Matches(str, #"\(([-+]?\d+\|[-+]?\d+)\)");
foreach (var match in matches)
{
Console.WriteLine(match);
}
Performance test
string str = "dsadsadsads(-123|12)sdakodskoakosdakodsadsayxvmyxcmxcym,§§¨§¨§(-43|23)sdadasdas";
StringBuilder bigstr = new StringBuilder();
for (int i = 0; i < 1000; i++)
{
bigstr.Append(str + "\n");
}
str = bigstr.ToString();
Regex regex = new Regex(#"\(([-+]?\d+\|[-+]?\d+)\)");
Stopwatch w = Stopwatch.StartNew();
var matches = regex.Matches(str);
var count = matches.Count;
w.Stop();
Console.WriteLine(w.Elapsed);
Output in my console. about 0.001 seconds.
I have one resume , i want to find user's contact number(Mobile no or Phone no)
from the resume, Need any idea or solution or any assistance for achieving the goal .
What i Have tried so far....
var numString = "";
string strData = ",38,,,,,,,,,,,,,,,,,,,,,,,,,,,,382350,,,,,0,,,,8141884584,,,,,,,,";
char[] separator = new char[] { ',' };
string[] strSplitArr = strData.Split(separator);
for (int q = 0; q < strSplitArr.Length; q++)
{
if (strSplitArr[q] != "")
{
int no = 0;
no = strSplitArr[q].Length;
if (no >= 10 && no <= 12)
{
numString += strSplitArr[q].ToString() + ", ";
}
}
}
I would suggest that you use Regular Expression
Here is a sample code to find US Phone numbers:
string text = MyInputMethod();
const string MatchPhonePattern =
#"\(?\d{3}\)?-? *\d{3}-? *-?\d{4}";
Regex rx = new Regex(MatchPhonePattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);
// Find matches.
MatchCollection matches = rx.Matches(text);
// Report the number of matches found.
int noOfMatches = matches.Count;
//Do something with the matches
foreach (Match match in matches)
{
//Do something with the matches
string tempPhoneNumber= match.Value.ToString(); ;
}
This question already has answers here:
How do I remove all non alphanumeric characters from a string except dash?
(13 answers)
Closed 9 years ago.
This is the code:
StringBuilder sb = new StringBuilder();
Regex rgx = new Regex("[^a-zA-Z0-9 -]");
var words = Regex.Split(textBox1.Text, #"(?=(?<=[^\s])\s+\w)");
for (int i = 0; i < words.Length; i++)
{
words[i] = rgx.Replace(words[i], "");
}
When im doing the Regex.Split() the words contain also strings with chars inside for exmaple:
Daniel>
or
Hello:
or
\r\nNew
or
hello---------------------------
And i need to get only the words without all the signs
So i tried to use this loop but i end that in words there are many places with ""
And some places with only ------------------------
And i cant use this as strings later in my code.
You don't need a regex to clear non-letters. This will remove all non-unicode letters.
public string RemoveNonUnicodeLetters(string input)
{
StringBuilder sb = new StringBuilder();
foreach(char c in input)
{
if(Char.IsLetter(c))
sb.Append(c);
}
return sb.ToString();
}
Alternatively, if you only want to allow Latin letters, you can use this
public string RemoveNonLatinLetters(string input)
{
StringBuilder sb = new StringBuilder();
foreach(char c in input)
{
if(c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
sb.Append(c);
}
return sb.ToString();
}
Benchmark vs Regex
public static string RemoveNonUnicodeLetters(string input)
{
StringBuilder sb = new StringBuilder();
foreach (char c in input)
{
if (Char.IsLetter(c))
sb.Append(c);
}
return sb.ToString();
}
static readonly Regex nonUnicodeRx = new Regex("\\P{L}");
public static string RemoveNonUnicodeLetters2(string input)
{
return nonUnicodeRx.Replace(input, "");
}
static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
StringBuilder sb = new StringBuilder();
//generate guids as input
for (int j = 0; j < 1000; j++)
{
sb.Append(Guid.NewGuid().ToString());
}
string input = sb.ToString();
sw.Start();
for (int i = 0; i < 1000; i++)
{
RemoveNonUnicodeLetters(input);
}
sw.Stop();
Console.WriteLine("SM: " + sw.ElapsedMilliseconds);
sw.Restart();
for (int i = 0; i < 1000; i++)
{
RemoveNonUnicodeLetters2(input);
}
sw.Stop();
Console.WriteLine("RX: " + sw.ElapsedMilliseconds);
}
Output (SM = String Manipulation, RX = Regex)
SM: 581
RX: 9882
SM: 545
RX: 9557
SM: 664
RX: 10196
keyboardP’s solution is decent – do consider it. But as I’ve argued in the comments, regular expressions are actually the correct tool for the job, you’re just making it unnecessarily complicated. The actual solution is a one-liner:
var result = Regex.Replace(input, "\\P{L}", "");
\P{…} specifies a Unicode character class we do not want to match (the opposite of \p{…}). L is the Unicode character class for letters.
Of course it makes sense to encapsulate this into a method, as keyboardP did. To avoid recompiling the regular expression over again, you should also consider pulling the regex creation out of the actual code (although this probably won’t give a big impact on performance):
static readonly Regex nonUnicodeRx = new Regex("\\P{L}");
public static string RemoveNonUnicodeLetters(string input) {
return nonUnicodeRx.Replace(input, "");
}
To help Konrad and keyboardP resolve their differences, I ran a benchmark test, using their code. It turns out that keyboardP's code is 10x faster than Konrad's code
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 = "asdf234!##*advfk234098awfdasdfq9823fna943";
DateTime start = DateTime.Now;
for (int i = 0; i < 100000; i++)
{
RemoveNonUnicodeLetters(input);
}
Console.WriteLine(DateTime.Now.Subtract(start).TotalSeconds);
start = DateTime.Now;
for (int i = 0; i < 100000; i++)
{
RemoveNonUnicodeLetters2(input);
}
Console.WriteLine(DateTime.Now.Subtract(start).TotalSeconds);
}
public static string RemoveNonUnicodeLetters(string input)
{
StringBuilder sb = new StringBuilder();
foreach (char c in input)
{
if (Char.IsLetter(c))
sb.Append(c);
}
return sb.ToString();
}
public static string RemoveNonUnicodeLetters2(string input)
{
var result = Regex.Replace(input, "\\P{L}", "");
return result;
}
}
}
I got
0.12
1.2
as output
UPDATE:
To see if it is the Regex compilation that is slowing down the Regex method, I put the regex in a static variable that is only constructed once.
static Regex rex = new Regex("\\P{L}");
public static string RemoveNonUnicodeLetters2(string input)
{
var result = rex.Replace(input,m => "");
return result;
}
But this had no effect on the runtime.
I have this string:
text = "book//title//page/section/para";
I want to go through it to find all // and / and their index.
I tried doing this with:
if (text.Contains("//"))
{
Console.WriteLine(" // index: {0} ", text.IndexOf("//"));
}
if (text.Contains("/"))
{
Console.WriteLine("/ index: {0} :", text.IndexOf("/"));
}
I was also thinking about using:
Foreach(char c in text)
but it will not work since // is not a single char.
How can I achieve what I want?
I tried this one also but did not display result
string input = "book//title//page/section/para";
string pattern = #"\/\//";
Regex rgx = new Regex(pattern, RegexOptions.IgnoreCase);
MatchCollection matches = rgx.Matches(input);
if (matches.Count > 0)
{
Console.WriteLine("{0} ({1} matches):", input, matches.Count);
foreach (Match match in matches)
Console.WriteLine(" " + input.IndexOf(match.Value));
}
Thank you in advance.
Simple:
var text = "book//title//page/section/para";
foreach (Match m in Regex.Matches(text, "//?"))
Console.WriteLine(string.Format("Found {0} at index {1}.", m.Value, m.Index));
Output:
Found // at index 4.
Found // at index 11.
Found / at index 17.
Found / at index 25.
Would it be possible using Split?
So:
string[] words = text.Split(#'/');
And then go through the words? You would have blanks, due to the //, but that might be possible?
If what you want is a list "book","title","page","section","para"
you can use split.
string text = "book//title//page/section/para";
string[] delimiters = { "//", "/" };
string[] result = text.Split(delimiters,StringSplitOptions.RemoveEmptyEntries);
System.Diagnostics.Debug.WriteLine(result);
Assert.IsTrue(result[0].isEqual("book"));
Assert.IsTrue(result[1].isEqual("title"));
Assert.IsTrue(result[2].isEqual("page"));
Assert.IsTrue(result[3].isEqual("section"));
Assert.IsTrue(result[4].isEqual("para"));
Sometin like:
bool lastCharASlash = false;
foreach(char c in text)
{
if(c == #'/')
{
if(lastCharASlash)
{
// my code...
}
lastCharASlash = true;
}
else lastCharASlash = false;
}
You can also do text.Split(#"//")
You could replace // and / with your own words and then find the last index of
string s = "book//title//page/section/para";
s = s.Replace("//", "DOUBLE");
s = s.Replace("/", "SINGLE");
IList<int> doubleIndex = new List<int>();
while (s.Contains("DOUBLE"))
{
int index = s.IndexOf("DOUBLE");
s = s.Remove(index, 6);
s = s.Insert(index, "//");
doubleIndex.Add(index);
}
IList<int> singleIndex = new List<int>();
while (s.Contains("SINGLE"))
{
int index = s.IndexOf("SINGLE");
s = s.Remove(index, 6);
s = s.Insert(index, "/");
singleIndex.Add(index);
}
Remember to first replace double, otherwise you'll get SINGLESINGLE for // instead of DOUBLE. Hope this helps.