search string inside string - c#

I'm working on application that's need search method I have listbox full with items every item have singer name and song title , I need be able to search the song title or singer name on same method that's what's I tried so far :
public void search_song()
{
for (int i = listbox_titles.Items.Count - 1; i >= 0; i--)
{
int char_count = listbox_titles.Items[i].ToString().Length;
if (listbox_titles.Items[i].ToString().ToLower().Contains(txt_to_search.Text) || listbox_titles.Items[i].ToString().StartsWith(txt_to_search.Text, StringComparison.Ordinal) || listbox_titles.Items[i].ToString().ToLower().Substring(0, char_count).Contains(txt_to_search.Text)) ;
{
//listbox_titles.SetSelected(i, true);
MessageBox.Show(listbox_titles.Items[i].ToString());
}
}
its work but only search from the beginning of items not middle
any ideas ??
this example of what's I want if item is **avicii waiting for love ** if I search waiting for love is should give me the item .

You just need to find the list box item that contains what you search for, so you don't need for StartsWith method, but since you're saying that your search method only works on the starting string, I can find that you're not converting the text to lower in StartsWith as in Contains, and that might what make the issue. So if your check is case insensitive you can just use the following:
public void search_song()
{
for (int i = listbox_titles.Items.Count - 1; i >= 0; i--)
{
int char_count = listbox_titles.Items[i].ToString().Length;
if (listbox_titles.Items[i].ToString().IndexOf(txt_to_search.Text, StringComparison.OrdinalIgnoreCase) >= 0)
{
//listbox_titles.SetSelected(i, true);
MessageBox.Show(listbox_titles.Items[i].ToString());
}
}

Make sure your code isn't like your original when you do get it working because you will always get the message box:
if (listbox_titles.Items[i].ToString().ToLower().Contains(txt_to_search.Text) ||
listbox_titles.Items[i].ToString().StartsWith(txt_to_search.Text, StringComparison.Ordinal) ||
listbox_titles.Items[i].ToString().ToLower().Substring(0, char_count).Contains(txt_to_search.Text)
) ;
{
//listbox_titles.SetSelected(i, true);
MessageBox.Show(listbox_titles.Items[i].ToString());
}
That green squiggle on the syntax highlighter is pointing you to a warning that it is an empty statement - you have a semi-colon at the end of the if, so your block of code is not conditional at all.
Edit:
public void search_song(string txt_to_search)
{
foreach(var t in listbox_titles.Items)
{
String s = t.ToString().ToLower();
if(s.Contains(txt_to_search.ToLower()))
{
//listbox_titles.SetSelected(i, true);
MessageBox.Show(s);
}
}
}
This works for me because it keeps the size of the lines down to a manageable level - obviously, you would need to index using a variable rather than foreach.
Edit:
If you need to know where the occurrences are you can always define an extension helper:
public void search_song(string txt_to_search)
{
foreach (var t in listbox_titles.Items)
{
if(txt_to_search.Occurrences(t.ToString(), false).Count > 0)
MessageBox.Show(t.ToString());
}
}
}
static class StringHelpers
{
public static List<int> Occurrences(this string pattern, string source, bool caseSensitive = true)
{
List<int> occurs = new List<int>();
if (String.IsNullOrEmpty(pattern) || String.IsNullOrWhiteSpace(pattern))
return occurs;
int index = 0;
if (!caseSensitive)
{
pattern = pattern.ToLower();
source = source.ToLower();
}
while (index < source.Length) // was (index < source.Length - 1)
{
if ((index = source.IndexOf(pattern, index)) < 0)
break;
occurs.Add(index);
++index;
}
return occurs;
}
}
Just capture the list and interrogate it.
Edit: just noticed that I had the scan stop short of the end (no idea why, old age brain fade perhaps). It probably won't make a major difference unless you are searching for single characters (which is what I happened to do!)

Related

Recommended way of checking if a certain string has a specified character more than once

Firstly I understand that there are several ways to do this and I do have some code which runs, but what I just wanted to find out was if anyone else has a recommended way to do this. Say I have a string which I already know that would have contain a specific character (a ‘,’ in this case). Now I just want to validate that this comma is used only once and not more. I know iterating through each character is an option but why go through all that work because I just want to make sure that this special character is not used more than once, I’m not exactly interested in the count per se. The best I could think was to use the split and here is some sample code that works. Just curious to find out if there is a better way to do this.
In summary,
I have a certain string in which I know has a special character (‘,’ in this case)
I want to validate that this special character has only been used once in this string
const char characterToBeEvaluated = ',';
string myStringToBeTested = "HelloWorldLetus,code";
var countOfIdentifiedCharacter = myStringToBeTested.Split(characterToBeEvaluated).Length - 1;
if (countOfIdentifiedCharacter == 1)
{
Console.WriteLine("Used exactly once as expected");
}
else
{
Console.WriteLine("Used either less than or more than once");
}
You can use string's IndexOf methods:
const char characterToBeEvaluated = ',';
string myStringToBeTested = "HelloWorldLetus,code";
string substringToFind = characterToBeEvaluated.ToString();
int firstIdx = myStringToBeTested.IndexOf(substringToFind, StringComparison.Ordinal);
bool foundOnce = firstIdx >= 0;
bool foundTwice = foundOnce && myStringToBeTested.IndexOf(substringToFind, firstIdx + 1, StringComparison.Ordinal) >= 0;
Try it online
You could use the LINQ Count() method:
const char characterToBeEvaluated = ',';
string myStringToBeTested = "HelloWorldLetus,code";
var countOfIdentifiedCharacter = myStringToBeTested.Count(x => x == characterToBeEvaluated);
if (countOfIdentifiedCharacter == 1)
{
Console.WriteLine("Used exactly once as expected");
}
else
{
Console.WriteLine("Used either less than or more than once");
}
This is the most readable and simplest approach and is great if you need to know the exact count but for your specific case #ProgrammingLlama's answer is better in terms of efficiency.
Adding another answer using a custom method:
public static void Main()
{
const char characterToBeEvaluated = ',';
string myStringToBeTested = "HelloWorldLetus,code";
var characterAppearsOnlyOnce = DoesCharacterAppearOnlyOnce(characterToBeEvaluated, myStringToBeTested);
if (characterAppearsOnlyOnce)
{
Console.WriteLine("Used exactly once as expected");
}
else
{
Console.WriteLine("Used either less than or more than once");
}
}
public static bool DoesCharacterAppearOnlyOnce(char characterToBeEvaluated, string stringToBeTested)
{
int count = 0;
for (int i = 0; i < stringToBeTested.Length && count < 2; ++i)
{
if (stringToBeTested[i] == characterToBeEvaluated)
{
++count;
}
}
return count == 1;
}
The custom method DoesCharacterAppearOnlyOnce() performs better than the method using IndexOf() for smaller strings - probably due to the overhead calling IndexOf. As the strings get larger the IndexOf method is better.

Checking every array member in an if statement to look for a specific array member

I'm trying to create a system where I have a string array where each member says the same thing ("Empty") but an if statement/foreach combo changes just one of those "Empty"s to a "Full" when a button is clicked. So first I start the if statement with something like
if (inv[0] == "Empty" || inv[1] == "Empty" || inv[2] == "Empty")
etc till it covers each member of the array making sure that there is at least one "Empty" (for it's supposed to only change an "Empty" to "Full" if there actually is an "Empty").
After that, I think I'm supposed to use a foreach, but I'm not sure how.
Anyway, any help would be appreciated. If you need me to send me my code, let me know.
You can find if any of item is empty like this.
bool isEmptyFound = false;
foreach (var item in inv)
if (item.Equals("Empty", StringComparison.OrdinalIgnoreCase))
{
isEmptyFound = true;
break;
}
//if isEmptyFound == true there is atleast one item that is "Empty"
You can not change item value by foreach you need to use simple for loop.
for (int i = 0; i < inv.Length; i++)
if (inv[i].Equals("Empty", StringComparison.OrdinalIgnoreCase))
{
inv[i] = "Full";
break;
}
Why not just use Array.IndexOf to find the index of a Empty and then change it to Full, like so:
int indexOfEmpty = Array.IndexOf(inv, "Empty");
//check if inv has a value set to "Empty"
if (indexOfEmpty != -1)
{
//change the "Empty" we found at indexOfEmpty to "Full"
inv[indexOfEmpty] = "Full";
}
If you are looking to do it manually with a loop, then you can just use a for loop like so:
bool foundEmpty = false;
for (int i = 0; i < inv.Length; i++)
{
if (inv[i] == "Empty")
{
inv[i] = "Full";
foundEmpty = true;
break;
}
}

How to iterate through multiple variables?

I'd like to create a short program to download several pictures from a website.
On a form, I would like to enter a root-link to a website with placeholders.
The placeholders can be defined with Start/End value and asc/desc.
For example: the original link is
google.de/1236-01.jpg
and I'd like to generate all links from
google.de/1236-1.jpg
up to
google.de/9955-12.jpg
So my input would be "google.de/[0]-[1].jpg" and placeholders are set to:
[0] = start 1236|end 9955|asc
[1] = start 1|end 12|asc
Via GetValidCharacters() I get a String-List of valid combinations for each entered placeholder (can be selected via ascending/descending + start&end).
The goal I'm struggling with is to build all combinations of this link, because I need to determine while runtime, how much placeholders I have.
My idea was to loop over an queue and enquueue each new build line, until there is none left with placeholders, but I don't know how to do this.
I need to make sure that all combinations are entered and they are entered only once.
private static void CreateDownloadList()
{
Queue<string> tmpQueue = new Queue<string>(); //temp queue
tmpQueue.Enqueue(DL_path); //DL_Path = google.de/[0]-[1].jpg
string line = "";
while ((line = tmpQueue.Dequeue()) != null) //not empty
{
if (line.Contains("[")) //placeholder
{
string tmpLine = line;
//how to determine, which placeholder is next?? need to know this and replace this with every combination, I get from GetValidCharacters(start, end, DESC)
}
else //done
{
_urlList.Add(line);
}
}
}
how about a simple for loop?
for (int i = 1236; i <= 9955; i++)
{
for (int j = 1; j <= 12; j++)
{
tmpQueue.Enqueue(string.Format("google.de/{0}-{1}.jpg", i, j));
}
}
I'm not going give you the full code but here is some pseudo code that would solve the problem.
given :
todostack -- stack object that holds a list of unresolved items
replace_map -- map object that holds marker string and map of all values
marker_list -- list of all markers
final_list -- list object that holds the results
(note you can probably use marker_list and replace_map in one object -- I have them separate to make my code clearer)
init :
push todostack with your starting string
set marker_list and replace_map to correct values (from parameters I assume)
clear final_list
algorithm :
while (there are any items in todostack)
{
curitem = todostack.pop
if (curitem contains a marker in marker_list)
{
loop for each replacement in replace_map
{
new_item = curitem replaced with replacement
todostack.push(new_item)
}
}
else
add curitem to final_list
}
#Hogan this was the hint to the correct way.
solution is this
private void CreateDownloadList()
{
Queue<string> tmpQueue = new Queue<string>();
tmpQueue.Enqueue(downloadPathWithPlaceHolders);
while(tmpQueue.Count > 0)
{
string currentItem = tmpQueue.Dequeue();
bool test = false;
if(currentItem.Contains("["))
{
foreach(Placeholder p in _placeholders)
{
if(currentItem.Contains(p.PlaceHolder))
{
foreach(string s in p.Replacements)
{
tmpQueue.Enqueue(currentItem.Replace(p.PlaceHolder, s));
}
test = true;
}
if(test)
break;
}
}
else
{
_downloadLinkList.Add(currentItem);
}
}
}

Find biggest concatenation word in array

I'm new to C#, can someone help me understand why my code doesnt work?
Seems like there something wrong with variable word which needs to be returned, but I don't understand what.
public virtual bool concatOnly()
{
int tmp = 0;
foreach (string word in words)
{
tmp += word.Length;
}
return (tmp <= word.Length);
}
I also don't really understand what I need to do in this:
public virtual void removeRepeat()
{
IEnumerator<string> iterator = words.GetEnumerator();
string checkWord = null;
while (iterator.MoveNext())
{
checkWord = iterator.Current;
foreach (string tmpWord in words)
{
if (tmpWord.Contains(checkWord) && checkWord.Length < tmpWord.Length)
{
iterator.Remove();
break;
}
}
}
}
Here's my full code
Update 3
In order to fix the second compile error (see Update 2), you need to remove from the list without doing so via Iterator, which has no remove method. One way would be the following, which saves up the indexes for removal after traversal by the iterator. Note that I remove the indexes in reverse order, so that the index numbers to be removed are not changed by prior removals.
public virtual void removeRepeat()
{
IEnumerator<string> iterator = words.GetEnumerator();
string checkWord = null;
List<int> removeIndexes = new List<int>();
int i = -1;
while (iterator.MoveNext())
{
checkWord = iterator.Current;
i++;
foreach (string tmpWord in words)
{
if (tmpWord.Contains(checkWord) && checkWord.Length < tmpWord.Length)
{
removeIndexes.Add(i);
break;
}
}
}
removeIndexes.Reverse();
foreach(var index in removeIndexes) {
words.RemoveAt(index);
}
}
Update 2
After fixing the first compile error (see my original answer below, which now works), your code is still giving this compile error main.cs(90,38): error CS1061: TypeSystem.Collections.Generic.IEnumerator' does not contain a definition for Remove' and no extension methodRemove' of typ
e `System.Collections.Generic.IEnumerator' could be found.
Update
I've changed my original answer to something that at least compiles. What I did is to change the original return (tmp <= word.Length); back to using word, which is the class member variable, not the local variable.
Original
Change the name of variable word in method concatOnly():
public virtual bool concatOnly()
{
int tmp = 0;
foreach (string w in words)
{
tmp += w.Length;
}
return (tmp <= word.Length);
}
This is because your class ConcatWord, of which concatOnly is a member method, already has a member variable named word: internal string word;.
FYI, the above shows that you also need to post the full code for the class ConcatWord. It's fine to give the link to the full code that you provided, that can be helpful, but everything required to reproduce the error also needs to be present in your question here at SO.

Binary search for List<object>

Hello I need some help in my library. I'm trying to implement a binary search from my List<> but its not working so well.
This is my Library class.
private class Library
{
List<object> library = new List<object>();
public void AddBook(string bookName, string bookAuthor, int bookIDNum)
{
//Add books to the library.
string bookEntry = bookName + " " + bookAuthor + " " + bookIDNum;
library.Add(bookEntry);
library.TrimExcess();
}
public void SearchLibrary(string bookName)
{
//Searches the library by title
library.Sort();
int low = 0;
int high = library.Count;
int mid = 0;
int steps = 0;
while(!bookName)
{
steps++;
mid = (low + high)/2;
if(bookName == library[mid])
{
return true;
}
else if(bookName < library[mid])
{
high = mid;
}
else
{
low = mid;
}
if(low > high-1 || high < low+1)
{
return false;
}
}
}
}
}
If there's a better way I can make a search method I would appreciate it, thank you.
Without commenting on the details of your algorithm, there are some issues with your code. You could've found all these issues by looking at the compiler's error messages.
You return true and false, yet your method specifies it returns void. Change that to bool instead.
public bool SearchLibrary(string bookName)
You do !bookName, where I presume you want to check whether it is null or not. You must do that explicitly in C#.
while (bookName != null)
You compare two strings, but the < operator is not overloaded for strings. Use CompareTo instead:
else if (bookName.CompareTo(library[mid]) < 0)
Not all code paths return a value. You'll have to return a value no matter what execution path it takes. For example, end your method with this:
return false;
Then there is an issue with your algorithm: it will run forever when there is no match. As I suspect this may be homework, I'll leave it an an exercise for the OP to solve this issue.
And if this isn't a homework exercise, you could've saved yourself some trouble:
The List<T> class has a method BinarySearch that uses the default comparer to compare the objects in the list.
library.Sort();
bool found = (library.BinarySearch(bookName) >= 0);

Categories

Resources