How to get delimiter count as a input? [duplicate] - c#

This question already has answers here:
Split a string with delimiters but keep the delimiters in the result in C#
(17 answers)
Closed 8 years ago.
in the program, i have to handle a input table like this.
a:1
b:2
c:3
?:6
#:14
obviously, delimiter is ":" and "\n"
however, input like this will catch an exception
::2
I want to make ':' store into a char list as well.
how do i modify these code?
and where should I put try-catch in?
String[] str;
str = textbox.Text.Trim().Split(':', '\n');
for (i = 0; i < str.Length; i = i + 2){
char tempC;
float tempFreq;
if (char.TryParse(str[i], out tempC))
c.Add(tempC);
if (float.TryParse(str[i + 1], out tempFreq))
freq.Add(tempFreq);
}

First you need to parse your text line by line.Use the Lines property for that
Then you can just check if the current line starts with :
var lines = textbox.Lines;
foreach(var line in lines)
{
if(line.StartsWith(':'))
{
c.Add(':');
float tempFreq;
if (float.TryParse(line.Split(':').Last(), out tempFreq))
freq.Add(tempFreq);
}
else
{
char tempC;
float tempFreq;
string[] parts = line.Split(':');
if (char.TryParse(parts[0], out tempC))
c.Add(tempC);
if (float.TryParse(parts[1], out tempFreq))
freq.Add(tempFreq);
}
}
Btw, I assumed it is WinForms, Lines property might not exist in WPF, if that is the case just split the text by newline character first, then iterate over the lines and do the same things.

You can use String.Split with StringSplitOptions.RemoveEmptyEntries, you can also split the lines first.
Your sample data with edge cases
var text = #"a:1
b:2
c:3
?:6
::2
#:14 ";
LINQ query which selects the char and the float as pair:
float freq = 0;
string[] lines = text.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
var lineTokens = lines.Select(l => l.Split(new[] { ':' }, StringSplitOptions.RemoveEmptyEntries))
.Where(arr => arr.Length == 2 && arr[0].Trim().Length == 1 && float.TryParse(arr[1].Trim(), out freq))
.Select(arr => new { chr = arr[0].Trim()[0], freq });
Output:
foreach(var x in lineTokens)
Console.WriteLine("Char:{0} Frequency:{1}", x.chr, x.freq);
Char:a Frequency:1
Char:b Frequency:2
Char:c Frequency:3
Char:? Frequency:6
Char:# Frequency:14

Related

How can I detect spaces in a textbox for later adding up all the numbers that the user has entered in the texbox C# winforms?

I want to make a small program, that people put their wedding expenses separated by spaces and return them the total. This in C# winforms.
The code:
string expenses = txEntrada.Text;
int add = 0;
string space = "";
for (int i = 0; i < expenses.Length; i++)
{
string substring = expenses.Substring(i, 1);
if (substring == space)
{
i++;
}
else
{
add += int.Parse(substring);
}
}
txSortida.Text = add.ToString();
I suggest something like this:
txSortida.Text = txEntrada
.Text
.Split(' ', StringSplitOptions.RemoveEmptyEntries)
.Sum(item => decimal.TryParse(item, out var cost) ? cost : 0.00m)
.ToString("c2");
Here we
Split the input by spaces ' ' and remove empty entry in order to tolerate leading, trailing and double spaces like " 123 456 " input.
We sum parsed values (since we work with cash, decimal is often the best choice; if you insist on int put int.TryParse instead); if value is of wrong format we ignore it (add 0m), i.e. "123 bla-bla-bla" 456 => 123 + 456 == 579
Finally, we format the result in some currency format (I've chosen c2)
This is all you need:
txSortida.Text =
txEntrada
.Text
.Split(' ', StringSplitOptions.RemoveEmptyEntries)
.Select(x => int.Parse(x))
.Sum()
.ToString();
In order to make this robust and not crash if user puts in extra spaces or non-numeric characters, I would recommend using the TryParse method for int. So first you would split the string with the Split method, using the option to RemoveEmptyEntries. Then go through that array with the TryParse method, adding in the value only if the parsing succeeds.
private void calculateSum()
{
int sum = 0;
string[] values = txEntrada.Text.Split(' ', StringSplitOptions.RemoveEmptyEntries);
List<string> goodValues = new List<string>();
foreach (var entry in values)
{
if(int.TryParse(entry, out int value))
{
sum += value;
goodValues.Add(entry);
}
}
txSortida.Text = sum.ToString();
txEntrada.Text = string.Join(" ", goodValues);
BeginInvoke(new Action(() => txEntrada.SelectAll()));
}
you can using expenses.Split To convert String to array based on space, and property StringSplitOptions.RemoveEmptyEntries remove Empty in array. then use Sum(x => Convert.ToInt32(x)) to sum the array as a number
int add = 0;
string expenses = txEntrada.Text;
txSortida.Text = expenses.Split(new char[] { ' ' },
StringSplitOptions.RemoveEmptyEntries)
.Sum(x => Convert.ToInt32(x));
You can use class Regex from namespace System.Text.RegularExpressions to split the input string into tokens (each token will be one of the items in the exprenses as a string).
Then convert each token into an int and sum them up.
Code example:
using System;
using System.Text.RegularExpressions;
//...
// Split into tokens:
string[] tokens = Regex.Split(expenses, " +"); // use + to inidcate one or more spaces between tokens.
// Sum up the values:
int sum = 0;
foreach (string token in tokens)
{
if (int.TryParse(token, out int val))
{
sum += val;
}
else
{
// Handle error ...
}
}
Console.WriteLine(sum);
Output:
321
In your actual code after calculating sum you can use:
txSortida.Text = sum.ToString();

How to remove texts after a character?

I have an array that holds user and passwords in user:pass form, and I like ro remove lines which pass is less than 8 characters or password uses repetitive chars like 111111,22222222222,...
I have tried string.take but it takes lines completely, I need conditional deletion.
public string[] lines;
//open file dialogue to load the user pass file
lines = File.ReadAllLines(openFileDialog1.FileName);
//delete button click event
//the place that I have problem
I have email:pass combination like so:
email1:1234567895121
email2:12345
email4:11111
email5"454545454545
and I would like the output to be like
email1:1234567895121
email5"454545454545
Just loop the characters of every line and see if the current is equal to the previous:
public string[] lines = File.ReadAllLines(openFileDialog1.FileName);
var filteredLines = new List<string>(lines);
foreach(var line in lines)
{
var pair = line.Split(':');
var mail = pair[0];
var pass = pair[1]; // may throw exception on invalid format of your line
for(int i = 1; i < pass.Length; i++)
{
if(pass[i] == pass[i - 1])
{
filteredLines.Remove(line);
break; // will break inner loop and continue on next line
}
}
}
string[] lines =
{
"email1:1234567895121",
"email2:12345",
"email3:22222222222",
"email4:11111",
"email5:454545454545"
};
lines = lines
.Where(s =>
{
string pass = s.Split(new[] { ':' }, 2)[1];
return pass.Length >= 8 && pass.Any(c => c != pass[0]);
})
.ToArray();
foreach (var s in lines)
Console.WriteLine(s);
Output:
email1:1234567895121
email5:454545454545

Get first word on every new line in a long string?

I am trying to add a leaderboard in my unity app
I have a long string as below(just an example, actual string is http pipe data from my web service, not manually stored):
string str ="name1|10|junk data.....\n
name2|9|junk data.....\n
name3|8|junk data.....\n
name4|7|junk data....."
I want to get the first word (string before the first pipe '|' like name1,name2...) from every line and store it in an array and then get the numbers (10,9,8... arter the '|') and store it in an other one.
Anyone know whats the best way to do this?
Fiddle here: https://dotnetfiddle.net/utp4HK
code below, you may want to revisit the algorithm for performance, but if that is not an issue, this will do the trick;
using System;
public class Program
{
public static void Main()
{
string str ="name1|10|junk data.....\nname2|9|junk data.....\nname3|8|junkdata.....\nname4|7|junk data.....";
foreach (var line in str.Split('\n'))
{
Console.WriteLine(line.Split('|')[0]);
}
}
}
First split by new-line characters:
string[] lines = str.Split(new string[]{Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
Then you can use LINQ to get both arrays:
var data = lines.Select(l => l.Trim().Split('|')).Where(arr => arr.Length > 1);
string[] names = data.Select(arr => arr[0].Trim()).ToArray();
string[] numbers = data.Select(arr => arr[1].Trim()).ToArray();
Check out this link on splitting strings: http://msdn.microsoft.com/en-us/library/ms228388.aspx
You could first create an array of strings (one for each line) by splitting the long string with \n as the delimeter.
Then, you could split each line with | as the delimeter. The name would be the 0th index of the array and the number would be the 1st index of the array.
First of all, you can't have a multi line string without using verbatim string literal. With using verbatim string literal, you can split your string based on \r\n or Environment.NewLine like;
string str = #"name1|10|junk data.....
name2|9|junk data.....
name3|8|junk data.....
name4|7|junk data.....";
var array = str.Split(new []{Environment.NewLine},
StringSplitOptions.RemoveEmptyEntries);
foreach (var item in array)
{
Console.WriteLine(item.Split(new[]{"|"},
StringSplitOptions.RemoveEmptyEntries)[0].Trim());
}
Output will be;
name1
name2
name3
name4
Try this:
string str ="name1|10|junk data.....\n" +
"name2|9|junk data.....\n" +
"name3|8|junk data.....\n" +
"name4|7|junk data.....";
string[] tempArray1 = str.Split('\n');
string[] tempArray2 = null;
string[,] newArray = null;
for (int i = 0; i < tempArray1.Length; i++)
{
tempArray2 = tempArray1[i].Split('|');
if (newArray[0, 0].ToString().Length == 0)
{
newArray = new string[tempArray1.Length, tempArray2.Length];
}
for (int j = 0; j < tempArray2.Length; j++)
{
newArray[i,j] = tempArray2[j];
}
}

Parse for words starting with # character in a string

I have to write a program which parses a string for words starting with '#' and return the words along with the # symbol.
I have tried something like:
char[] delim = { '#' };
string[] strArr = commenttext.Split(delim);
return strArr;
But it returns all the words without '#' in an array.
I need something pretty straight forward.No LINQ like things
If the string is "abc #ert #xyz" then I should get back #ert and #xyz.
If you define "word" as "separated by spaces" then this would work:
string[] strArr = commenttext.Split(' ')
.Where(w => w.StartsWith("#"))
.ToArray();
If you need something more complex, a Regular Expression might be more appropriate.
I need something pretty straight forward.No LINQ like things>
The non-Linq equivalent would be:
var words = commenttext.Split(' ');
List<string> temp = new List<string>();
foreach(string w in words)
{
if(w.StartsWith("#"))
temp.Add(w);
}
string[] strArr = temp.ToArray();
If you're against using Linq, which you should not be unless you're required to use older .NET versions, an approach along these lines would suit your needs.
string[] words = commenttext.Split(delimiter);
for (int i = 0; i < words.Length; i++)
{
string word = words[i];
if (word.StartsWith(delimiter))
{
// save in array / list
}
}
const string test = "#Amir abcdef #Stack #C# mnop xyz";
var splited = test.Split(' ').Where(m => m.StartsWith("#")).ToList();
foreach (var b in splited)
{
Console.WriteLine(b.Substring(1, b.Length - 1));
}
Console.ReadKey();

How do I convert spaces, except for those within quotes, to commas in C#?

Suppose I have a string like this:
one two three "four five six" seven eight
and I want to convert it to this:
one,two,three,"four five six",seven,eight
What's the easiest way to do this in C#?
Assuming that quotes are inescapable you can do the following.
public string SpaceToComma(string input) {
var builder = new System.Text.StringBuilder();
var inQuotes = false;
foreach ( var cur in input ) {
switch ( cur ) {
case ' ':
builder.Append(inQuotes ? cur : ',');
break;
case '"':
inQuotes = !inQuotes;
builder.Append(cur);
break;
default:
builder.Append(cur);
break;
}
}
return builder.ToString();
}
static string Space2Comma(string s)
{
return string.Concat(s.Split('"').Select
((x, i) => i % 2 == 0 ? x.Replace(' ', ',') : '"' + x + '"').ToArray());
}
My first guess is to use a parser that's already written and simple change the delimiter and quote character fit your needs (which are and " respectively).
It looks like this is available to you in C#:
http://msdn.microsoft.com/en-us/library/microsoft.visualbasic.fileio.textfieldparser.aspx
Perhaps if you changed the delimiter to " ", it may suit your needs to read in the file and then it's just a matter of calling String.Join() a for each line.
I would use the Regex class for this purpose.
Regular expressions can be used to match your input, break it down into individual groups, which you can then reassemble however you want. You can find documentation on the regex classes here.
Regex rx = new Regex( "(\w)|([\"]\w+[\"])" );
MatchCollection matches = rx.Matches("first second \"third fourth fifth\" sixth");
string.Join( ", ", matches.Select( x => x.Value ).ToArray() );
Here's a more reusable function that I came up with:
private string ReplaceWithExceptions(string source, char charToReplace,
char replacementChar, char exceptionChar)
{
bool ignoreReplacementChar = false;
char[] sourceArray = source.ToCharArray();
for (int i = 0; i < sourceArray.Length; i++)
{
if (sourceArray[i] == exceptionChar)
{
ignoreReplacementChar = !ignoreReplacementChar;
}
else
{
if (!ignoreReplacementChar)
{
if (sourceArray[i] == charToReplace)
{
sourceArray[i] = replacementChar;
}
}
}
}
return new string(sourceArray);
}
Usage:
string test = "one two three \"four five six\" seven eight";
System.Diagnostics.Debug.WriteLine(ReplaceWithExceptions(test, char.Parse(" "),
char.Parse(","), char.Parse("\"")));
This may be overkill, but if you believe the problem may generalize, such as having a need to split by other types of characters, or having additional rules that define a token, you should consider either using a parser generator such as Coco or writing a simple one on your own. Coco/R, for instance, will build generate a lexer and parser from an EBNF grammar you provide. The lexer will be a DFA, or a state machine, which is a generalized form of the code provided by JaredPar. Your grammar definition for Coco/R would look like this:
CHARACTERS
alphanum = 'A'..'Z' + 'a'..'z' + '0'..'9'.
TOKENS
unit = '"' {alphanum|' '} '"' | {alphanum}.
Then the produced lexer will scan and tokanize your input accordingly.
Per my comment to the original question, if you don't need the quotes in the final result, this will get the job done. If you do need the quotes, feel free to ignore this.
private String SpaceToComma(string input)
{
String[] temp = input.Split(new Char[] { '"' }, StringSplitOptions.RemoveEmptyEntries);
for (Int32 i = 0; i < temp.Length; i += 2)
{
temp[i] = temp[i].Trim().Replace(' ', ',');
}
return String.Join(",", temp);
}
#Mehrdad beat me to it but guess I'll post it anyway:
static string Convert(string input)
{
var slices = input
.Split('"')
.Select((s, i) => i % 2 != 0
? #"""" + s + #""""
: s.Trim().Replace(' ', ','));
return string.Join(",", slices.ToArray());
}
LINQified and tested :-) ... For a full console app: http://pastebin.com/f23bac59b

Categories