I have Googled this a LOT but my C# skills are pretty terrible and I just can't see why this isn't working.
I have a string which comes from a session object, which I don't have any control over setting. The string contains some sentences separated by six underscores. e.g.:
Sentence number one______Sentence number two______Sentence number three etc
I want to split this string by the six underscores and return each item in the resultant array.
Here's the code I have:
string itemsPlanner = HttpContext.Current.Session["itemsPlanner"].ToString();
string[] arrItemsPlanner = itemsPlanner.Split(new string[] { "______" }, StringSplitOptions.None);
foreach (string i in arrItemsPlanner)
{
newItemsPlanner += "debug1: " + i; //This returns what looks like a number, as I'd expect, starting at zero and iterating by one each loop.
int itemNumber;
try
{
itemNumber = Convert.ToInt32(i);
string sentence = arrItemsPlanner[itemNumber].ToString();
}
catch (FormatException e)
{
return "Input string is not a sequence of digits.";
}
catch (OverflowException e)
{
return "The number cannot fit in an Int32.";
}
finally
{
return "Fail!"
}
}
Whenever I run this, the session is being retreived successfully but the line which says: itemNumber = Convert.ToInt32(i); fails every time and I get an error saying "Input string is not a sequence of digits."
Can anyone point me in the right direction with this please?
Many thanks!
If you just want to get each sentence and do something with it, this will do the trick:
string itemsPlanner = HttpContext.Current.Session["itemsPlanner"].ToString();
string[] arrItemsPlanner = itemsPlanner.Split("______");
foreach (string i in arrItemsPlanner)
{
// Do something with each sentence
}
You can split over a string as well as char (or char[]). In the foreach 'i' will be the value of the sentence, so you can concatenate it or process it or do whatever :)
If I've misunderstood, my apologies. I hope that helps :)
in your case i is not a number, it's the actual element in the array. A foreach loop has no iteration variable, you only have access to the actual element being iterated through i.
So first loop itareation i is Sentence number one, then Sentence number two.
If you want the number, you have to use a for loop instead.
So something like this
for( int i = 0; i < arrItemsPlanner.length; i++ ){
//on first iteration here
//i is 0
//and arrItemsPlanner[i] id "Sentence number one"
}
Hope it helps.
From your example i does not contain a valid integer number, thus Convert.ToInt32 fails. The foreach loop sets i with the current item in the sentences array, so basically i always contains one of the sentences in your main string. If you want i to be the index in the array, use a for loop.
Example from MSDN.
string words = "This is a list of words______with a bit of punctuation" +
"______a tab character.";
string [] split = words.Split(new Char [] {'_'}, StringSplitOptions.RemoveEmptyEntries);
foreach (string s in split) {
if (s.Trim() != "")
Console.WriteLine(s);
}
Do you need to trim your string before converting to a number? if thats not you may want to use Int32.tryParse()
In your sample code foreach (string i in arrItemsPlanner) 'i' will get the string value of arrItemsPlanner one by one.
For exmaple on first iteration it will have 'Sentence number one' which is obviously not a vlid ont, hence your conversion failed.
i only contains one of the string fragment which will be : number one Sentence number two and Sentence number three. If you want it to contain an int representing ht index, use :
1) a for loop
2) an int defined before your foreach and increase it (myInt++) in the foreach code !
Related
I was trying to create a list from a user input with something like this:
Create newlist: word1, word2, word3, etc...,
but how do I get those words one by one only by using commas as references going through them (in order) and placing them into an Array etc? Example:
string Input = Console.ReadLine();
if (Input.Contains("Create new list:"))
{
foreach (char character in Input)
{
if (character == ',')//when it reach a comma
{
//code goes here, where I got stuck...
}
}
}
Edit: I didn`t know the existence of "Split" my mistake... but at least it would great if you could explain me to to use it for the problem above?
You can use this:
String words = "word1, word2, word3";
List:
List<string> wordsList= words.Split(',').ToList<string>();
Array:
string[] namesArray = words.Split(',');
#patrick Artner beat me to it, but you can just split the input with the comma as the argument, or whatever you want the argument to be.
This is the example, and you will learn from the documentation.
using System;
public class Example {
public static void Main() {
String value = "This is a short string.";
Char delimiter = 's';
String[] substrings = value.Split(delimiter);
foreach (var substring in substrings)
Console.WriteLine(substring);
}
}
The example displays the following output:
Thi
i
a
hort
tring.
Currently fiddling with a little project I'm working on, it's a count down type game (the tv show).
Currently, the program allows the user to pick a vowel or consonant to a limit of 9 letters and then asks them to input the longest word they can think of using these 9 letters.
I have a large text file acting as a dictionary that i search through using the user inputted string to try match a result to check if the word they entered is a valid word. My problem, is that I want to then search my dictionary for the longest word made up of the nine letters, but i just cant seem to find a way to implement it.
So far I've tried putting every word into an array and searching through each element to check if it contains the letters but this wont cover me if the longest word that can be made out of the 9 letters is a 8 letter word. Any idea's?
Currently I have this (This is under the submit button on the form, sorry for not providing code or mentioning it's a windows form application):
StreamReader textFile = new StreamReader("C:/Eclipse/Personal Projects/Local_Projects/Projects/CountDown/WindowsFormsApplication1/wordlist.txt");
int counter1 = 0;
String letterlist = (txtLetter1.Text + txtLetter2.Text + txtLetter3.Text + txtLetter4.Text + txtLetter5.Text + txtLetter6.Text + txtLetter7.Text + txtLetter8.Text + txtLetter9.Text); // stores the letters into a string
char[] letters = letterlist.ToCharArray(); // reads the letters into a char array
string[] line = File.ReadAllLines("C:/Eclipse/Personal Projects/Local_Projects/Projects/CountDown/WindowsFormsApplication1/wordlist.txt"); // reads every line in the word file into a string array (there is a new word on everyline, and theres 144k words, i assume this will be a big performance hit but i've never done anything like this before so im not sure ?)
line.Any(x => line.Contains(x)); // just playing with linq, i've no idea what im doing though as i've never used before
for (int i = 0; i < line.Length; i++)// a loop that loops for every word in the string array
// if (line.Contains(letters)) //checks if a word contains the letters in the char array(this is where it gets hazy if i went this way, i'd planned on only using words witha letter length > 4, adding any words found to another text file and either finding the longest word then in this text file or keeping a running longest word i.e. while looping i find a word with 7 letters, this is now the longest word, i then go to the next word and it has 8 of our letters, i now set the longest word to this)
counter1++;
if (counter1 > 4)
txtLongest.Text += line + Environment.NewLine;
Mike's code:
using System;
using System.Collections.Generic;
using System.Linq;
class Program
static void Main(string[] args) {
var letters = args[0];
var wordList = new List<string> { "abcbca", "bca", "def" }; // dictionary
var results = from string word in wordList // makes every word in dictionary into a seperate string
where IsValidAnswer(word, letters) // calls isvalid method
orderby word.Length descending // sorts the word with most letters to top
select word; // selects that word
foreach (var result in results) {
Console.WriteLine(result); // outputs the word
}
}
private static bool IsValidAnswer(string word, string letters) {
foreach (var letter in word) {
if (letters.IndexOf(letter) == -1) { // checks if theres letters in the word
return false;
}
letters = letters.Remove(letters.IndexOf(letter), 1);
}
return true;
}
}
Here's an answer I knocked together in a couple of minutes which should do what you want. As others have said, this problem is complex and so the algorithm is going to be slow. The LINQ query evaluates each string in the dictionary, checking whether the supplied letters can be used to produce said word.
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main(string[] args) {
var letters = args[0];
var wordList = new List<string> { "abcbca", "bca", "def" };
var results = from string word in wordList
where IsValidAnswer(word, letters)
orderby word.Length descending
select word;
foreach (var result in results) {
Console.WriteLine(result);
}
}
private static bool IsValidAnswer(string word, string letters) {
foreach (var letter in word) {
if (letters.IndexOf(letter) == -1) {
return false;
}
letters = letters.Remove(letters.IndexOf(letter), 1);
}
return true;
}
}
So where are you getting stuck? Start with the slow brute-force method and just find all the words that contain all the characters. Then order the words by length to get the longest. If you don't want to return a word that is shorter than the number of characters being sought (which I guess is only an issue if there are duplicate characters???), then add a test and eliminate that case.
I've had some more thoughts about this. I think the way to do it efficiently is by preprocessing the dictionary, ordering the letters in each word in alphabetical order and ordering the words in the list alphabetically too (you'll probably have to use some sort of multimap structure to store the original word and the sorted word).
Once you've done that you can much more efficiently find the words that can be generated from your pool of letters. I'll come back and flesh out an algorithm for doing this later, if someone else doesn't beat me to it.
Step 1: Construct a trie structure with each word sort by letter.
Example: EACH is sorted to ACEH is stored as A->C->E->H->(EACH, ACHE, ..) in the trie (ACHE is an anagram of EACH).
Step 2: Sort the input letters and find find the longest word corresponding to that set of letters in the trie.
Have you tried implementing something like this? It would be great to see your code you have tried.
string[] strArray = {"ABCDEFG", "HIJKLMNOP"};
string findThisString = "JKL";
int strNumber;
int strIndex = 0;
for (strNumber = 0; strNumber < strArray.Length; strNumber++)
{
strIndex = strArray[strNumber].IndexOf(findThisString);
if (strIndex >= 0)
break;
}
System.Console.WriteLine("String number: {0}\nString index: {1}",
strNumber, strIndex);
This must do the job :
private static void Main()
{
char[] picked_char = {'r', 'a', 'j'};
string[] dictionary = new[] {"rajan", "rajm", "rajnujaman", "rahim", "ranjan"};
var words = dictionary.Where(word => picked_char.All(word.Contains)).OrderByDescending(word => word.Length);
foreach (string needed_words in words)
{
Console.WriteLine(needed_words);
}
}
Output :
rajnujaman
ranjan
rajan
rajm
I have the following string which i would like to retrieve some values from:
============================
Control 127232:
map #;-
============================
Control 127235:
map $;NULL
============================
Control 127236:
I want to take only the Control . Hence is there a way to retrieve from that string above into an array containing like [127232, 127235, 127236]?
One way of achieving this is with regular expressions, which does introduce some complexity but will give the answer you want with a little LINQ for good measure.
Start with a regular expression to capture, within a group, the data you want:
var regex = new Regex(#"Control\s+(\d+):");
This will look for the literal string "Control" followed by one or more whitespace characters, followed by one or more numbers (within a capture group) followed by a literal string ":".
Then capture matches from your input using the regular expression defined above:
var matches = regex.Matches(inputString);
Then, using a bit of LINQ you can turn this to an array
var arr = matches.OfType<Match>()
.Select(m => long.Parse(m.Groups[1].Value))
.ToArray();
now arr is an array of long's containing just the numbers.
Live example here: http://rextester.com/rundotnet?code=ZCMH97137
try this (assuming your string is named s and each line is made with \n):
List<string> ret = new List<string>();
foreach (string t in s.Split('\n').Where(p => p.StartsWith("Control")))
ret.Add(t.Replace("Control ", "").Replace(":", ""));
ret.Add(...) part is not elegant, but works...
EDITED:
If you want an array use string[] arr = ret.ToArray();
SYNOPSYS:
I see you're really a newbie, so I try to explain:
s.Split('\n') creates a string[] (every line in your string)
.Where(...) part extracts from the array only strings starting with Control
foreach part navigates through returned array taking one string at a time
t.Replace(..) cuts unwanted string out
ret.Add(...) finally adds searched items into returning list
Off the top of my head try this (it's quick and dirty), assuming the text you want to search is in the variable 'text':
List<string> numbers = System.Text.RegularExpressions.Regex.Split(text, "[^\\d+]").ToList();
numbers.RemoveAll(item => item == "");
The first line splits out all the numbers into separate items in a list, it also splits out lots of empty strings, the second line removes the empty strings leaving you with a list of the three numbers. if you want to convert that back to an array just add the following line to the end:
var numberArray = numbers.ToArray();
Yes, the way exists. I can't recall a simple way for It, but string is to be parsed for extracting this values. Algorithm of it is next:
Find a word "Control" in string and its end
Find a group of digits after the word
Extract number by int.parse or TryParse
If not the end of the string - goto to step one
realizing of this algorithm is almost primitive..)
This is simplest implementation (your string is str):
int i, number, index = 0;
while ((index = str.IndexOf(':', index)) != -1)
{
i = index - 1;
while (i >= 0 && char.IsDigit(str[i])) i--;
if (++i < index)
{
number = int.Parse(str.Substring(i, index - i));
Console.WriteLine("Number: " + number);
}
index ++;
}
Using LINQ for such a little operation is doubtful.
ArrayList fileList = new ArrayList();
private void button2_Click(object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
string line;
// Read the file and display it line by line.
System.IO.StreamReader file = new System.IO.StreamReader(openFileDialog1.FileName);
while ((line = file.ReadLine()) != null)
{
// Puts elements in table
fileList.Add(line.Split(';'));
}
file.Close();
}
for (int i = 0; i < fileList.Count; i++)
{
for (int x = 0; x < (fileList[i] as string[]).Length; x++)
{
// if (x ==0)
// {
//fileList[0] must Be int
// }
// if (x==1)
//fileList[1] must be string
this.textBox2.Text += ((fileList[i] as string[])[x] + " ");
}
this.textBox2.Text += Environment.NewLine;
}
}
I am so far here.
I take the elements from a CSV file.
I need now to be sure that the 1 column has only numbers-integers (1,2,3,4,5), the second column has only names(so it will have the type string or character), the third surnames etc. etc.
The rows are presented like this : 1;George;Mano;
How can I be sure that the CSV file has the correct types?
I think that any more code about this problem will be placed inside the 2 for statements.
Thank you very much,
George.
I think your question needs more work.
You don't show your declaration for filelist. Whatever it is, there is no reason to convert it to string[] just to get the length. The length with be the same no matter what type it is. You cannot use this method to determine which items are strings.
You'll need to loop through the items and see if they contain only digits or whatever.
Also, your code to read CSV files is not quote right. CSV files are comma-separated. And it's possible that they could contain commas within double quotes. These commas should be ignored. A better way to read CSV files can be seen here.
An Arraylist contains object.
System.IO.StreamReader.ReadLine returns a String.
Checking the value of the first line read and trying to convert the string into an integer would be a valid approach.
Your current approach is adding the String that is returned by System.IO.StreamReader.ReadLine into your collection which you later turn into a String[] by using the String.Split method.
Your other requirements will be a greal more difficult because every line you are reading is a String already. So you would have to look at each character within the string to determine if it appears to be a name.
In other words you might want to find a different way to provide an input. I would agree that a regular expression might be the best way to get rid of junk data.
Edit: Now that we know it's really CSV, here's a columnar answer ;-)
Your ArrayList contains string[], so you need to verify that each array has the appropriate type of string.
for (int i = 0; i < fileList.Count; i++)
{
string[] lineItems = (string[])fileList[i];
if (!Regex.IsMatch (lineItems[0], "^\d+$")) // numbers
throw new ArgumentException ("invalid id at row " + i);
if (!Regex.IsMatch (lineItems[1], "^[a-zA-Z]+$")) // surnames - letters-only
throw new ArgumentException ("invalid surname at row " + i);
if (!Regex.IsMatch (lineItems[2], "^[a-zA-Z]+$")) // names - letters-only
throw new ArgumentException ("invalid name at row " + i);
}
You can use Regex class.
fileList[0] must Be int:
int x;
if(int.TryParse(fileList[0], out x)){ //do whatever here and x will have that integer value. TryParse will return false if it's not an integer so the if will not fire}
fileList[1] must be string :
iterate over the string and check each element is a letter. look at the char. methods for the appropriate one.
I have a string which contains, lets say word "key" 5 times. Each time I see the word "key" in that string I want to print some text. How can I parse that string, find all "key" words and print the texts accordingly? 5 words "key" - 5 printed texts. This needs to be done in C#.
Thanks in advance.
How about using Regex.Matches:
string input = ...
string toPrint = ...
foreach (Match m in Regex.Matches(input, "key"))
Console.WriteLine(toPrint);
EDIT: If by "word", you mean 'whole words', you need a different regex, such as:
#"\bkey\b"
Inside a loop, you can use the substring() method which offers the starting position parameter, and with each iteration you would advance the starting position; loop exits when you reach the string-not-found condition. EDIT: as for printing the text, that would depend on where you want to print it. EDIT2: You also need to consider whether the target string can appear in a manner you would not consider a true "hit":
The key to success, the master key, is getting off your keyster...
I have an extension method I use for strings to get Indexes of a substring since .Net only provides IndexOf (single result for first substring match).
public static class Extensions
{
public static int[] IndexesOf(this string str, string sub)
{
int[] result = new int[0];
for(int i=0; i < str.Length; ++i)
{
if(i + sub.Length > str.Length)
break;
if(str.Substring(i,sub.Length).Equals(sub))
{
Array.Resize(ref result, result.Length + 1);
result[result.Length - 1] = i;
}
}
return result;
}
}
You could use the extension method for all instances of key to print something
int[] indexes = stringWithKeys.IndexesOf("key");
foreach(int index in indexes)
{
// print something
}
I know my code example may be longest but the extension method is reusable and you could place it in a "utility" type library for later use.
If it is a multiple word string, you could use LINQ.
string texttosearch;
string texttofind;
string[] source = texttosearch.Split(new char[] { '.', '?', '!', ' ', ';', ':', ',' }, StringSplitOptions.RemoveEmptyEntries);
var matchQuery = from word in source
where word.ToLowerInvariant() == texttofind.ToLowerInvariant()
select word;
foreach (string s in matchquery)
console.writeline(whatever you want to print);