This question already has answers here:
Fastest way to find strings in a file
(5 answers)
Closed 5 years ago.
So I have a text file which I would like to search through for a number and if it is found then outputs a message number is found and if not then not found.
Currently I have read the text file into a string and asked the user what number they would like to search for. The part I am stuck on is the code for the linear search for a string. I want to look for a string because other files I will use may contain words.
Code So far:
public static void search() // Search for values
{
Console.WriteLine("Enter 1 to search through days");
int operation = Convert.ToInt32(Console.ReadLine());
if (operation == 1)
{
String[] myArray = File.ReadAllLines("Data1/Day_1.txt");
Console.WriteLine("Enter number to search");
String myString = Console.ReadLine();
}
}
I have seen some code for a linear search but not sure how to apply it properly to my example. I understand how it works but problem is with getting code in the correct order. Not too good at coding in c#. Any help would be much appreciated. Thanks
Generic Linear Search Code :
static int Search(string[] list, string elementSought)
{
bool found = false;
int max = list.Length - 1;
int currentElement = 0;
do
{
if (list[currentElement] == elementSought)
{
found = true;
}
else
{
currentElement = currentElement + 1;
}
} while (!(found == true || currentElement > max));
if (found == true)
{
return currentElement;
}
else
{
return -1;
}
}
Update:
public static void search() // Search for values
{
Console.WriteLine("1=Day 2=Depth");
int operation = Convert.ToInt32(Console.ReadLine());
if (operation == 1)
{
String[] myArray = File.ReadAllLines("Data1/Day_1.txt");
}
else if (operation == 2)
{
String[] myArray = File.ReadAllLines("Data1/Months_1.txt");
}
Console.WriteLine("Enter number to search");
String myString = Console.ReadLine();
int i = 0;
int j = 0;
var regex = new Regex(myString);
foreach (string array in myArray)
{
if (regex.IsMatch(array))
{
i++;
}
else if (regex.IsMatch(array))
{
j++;
}
}
if (i > 0)
{
Console.WriteLine("Found match! - {1} Appeared {0} time(s)",i,myString);
}
else if(j == 0)
{
Console.WriteLine("No Match for {0} in Data", myString);
}
Console.ReadLine();
}
How do I change it so that if I choose the second file that it selects that as the one to use as my Array?
You can use Array.IndexOf. It will return -1 if the item is not found int the array, otherwise the index of its first occurrence.
Example (console app)
static void Main(string[] args)
{
string[] list = {"xxx", "yyy", "aaa", "bbb"};
var found = Search(list, "gggg");
}
static bool Search(string[] list, string elementSought)
{
var index = Array.IndexOf(list, elementSought);
var found = index != -1;
return found;
}
you've overcomplicated the task at hand, simply use a for loop for a linear search or using Linq:
static int Search(string[] list, string elementSought)
{
return list.ToList().FindIndex(s => s == elementSought);
}
You need to loop through your array of strings in search of a match. Use a regex to check for a match.
Console.WriteLine("Enter number to search");
String myString = Console.ReadLine();
var regex = new Regex(myString);
foreach (string array in myArray)
if (regex.IsMatch(array))
Console.WriteLine("Found match!");
Related
This question already has answers here:
How do I create a terminable while loop in console application?
(7 answers)
Closed 3 years ago.
I started a C# course now and there is an assignment where I have to create a "palindrome detector" program. Point is that user inputs some word or sentence, then I have to remove chars like ,.;:!? and space from it. I have done that with two different methods, because char method can not remove space so I wrote another method for it.
After "cleaning" operation program reversing input what user gave, and comparing original user input and reversed user input to each other. It they are same it prints "It is palindrome", if they are different it prints "It is not palindrome". That is working fine, BUT THE PROBLEM IS I have to put them in for loop. It have to ask input again and again, until user give empty.
This would be very easy, but somehow I can not do it.
Here is my code:
using System;
namespace Palindromi
{
class Program
{
static void Main()
{
Console.WriteLine("Hei! Tervetuloa palindromin tunnistusohjelmaan. Tämä tunnistaa, onko syöttämäsi sana sama toisinpäin!");
Console.Write("Anna teksti (tyhjä lopettaa): ");
string userinput = Console.ReadLine(); //userinput is user's input, this is what you have to modify. remove some chars and reverse it.
if (userinput == "")
{
Console.ReadLine();//when i have loop this have to be "break". This meant to break for loop when i have it.
}
char[] removechars = { '.', ':', ';', ',', '!', '?' };//this is the list of "have to be removed" chars
string userinput_without_chars = userinput.Trim(removechars); //this method remove chars which are listed
string userinput_without_chars_space = userinput_without_chars.Replace( " ", ""); //replace space with empty
string reverse_string, reversed;
reverse_string = userinput_without_chars_space;
reversed = "";
int len;
len = userinput_without_chars_space.Length - 1;
while (len >= 0)
{
reversed = reversed + reverse_string[len];
len--;
}
Console.WriteLine("Sana käännettynä on {0}", reversed); //tells user input reversed
if (userinput_without_chars_space == reversed)//check is the userinput same than reversed user input
{
Console.Write("On palindromi.");//it is palindrome
}
else
{
Console.Write("Ei ole palindromi.");//it is not palindrome
}
}
}
}
You could potentially do something along these lines:
var running = true;
while(running)
{
var input = Console.ReadLine().ToLower();
var phrase = input.Sanitize(new List<string>() {".", ",", "?", "!", "'", "&", "%", "$", " "});
if(phrase.IsPalindrome())
Console.Writeline("Input was palindrome.");
}
public static string Sanitize(this string input, IList<string> punctuation) =>
String.Join(String.Empty, input.Where(character => punctuation.Contains(character) == false));
public static bool IsPalindrome(this string sentence)
{
for (int l = 0, r = sentence.Length - 1; l < r; l++, r--)
if (sentence[l] != sentence[r])
return false;
return true;
}
public static void Close(string input)
{
// Some logic to see if the application should stop.
}
You could create another method that looks for commands, or keystrokes, then sets the boolean to run as false. Which would break the infinite loop. You could also do an abrupt close with Environment.Exit.
The very simplest approach is replace your Console.ReadLine() where you want to break to return.
Alternatively, you could wrap the logic in another while loop.
while (userinput != "")
{
// Remove chars
// rest of your logic
/* IMPORTANT */
userinput = Console.Readline();
}
To remove the symbols from the input, you can use the Regex.Replace method. In this case, you can be sure, that the specified symbols will be correctly removed from the input string. Note, that you can handle the whitespaces along with other characters you mentioned, like in the code snippet below:
var CharactersToRemove { get; set; } = " ,.;:!?";
var processedInput = Regex.Replace(input.ToLower(), $"[{CharactersToRemove}]", string.Empty);
Note, that here I used input.ToLower() to convert the input to a lowercase string. This will make the palindrome tests case-insensitive. Should you need case-sensitive palindrome tests, just remove the .ToLower() part.
There is no need to reverse the input string to check if it is a palindrome. You can check this within one for loop as follows:
bool CheckForBeingaAPalindrome(string input)
{
var frontIndex = 0;
var tailIndex = input.Length - 1;
for (; frontIndex < tailIndex;)
{
if (input[frontIndex] != input[tailIndex])
return false;
++frontIndex;
--tailIndex;
}
return true;
}
Note, that in this case you only iterate over the elements of the input string once. This approach will give you al least 4 times better performance than the one you used.
Below, you can find a complete minimal working solution to your problem.
using System.Text.RegularExpressions;
using static System.Console;
namespace Assignment
{
public static class PalindromeFinder
{
public static string CharactersToRemove { get; set; } = " ,.;:!?";
public static bool IsPalindrome(string input)
{
var processedInput = RemoveUnnecessaryCharacters(input);
return CheckForBeingAPalindrome(processedInput);
}
private static string RemoveUnnecessaryCharacters(string input)
{
return Regex.Replace(input.ToLower(), $"[{CharactersToRemove}]", string.Empty);
}
private static bool CheckForBeingAPalindrome(string input)
{
var frontIndex = 0;
var tailIndex = input.Length - 1;
for (; frontIndex < tailIndex;)
{
if (input[frontIndex] != input[tailIndex])
return false;
++frontIndex;
--tailIndex;
}
return true;
}
}
public class Program
{
private static void Main(string[] args)
{
ContinuouslyCheckUserInputForBeingAPalindrome();
}
private static void ContinuouslyCheckUserInputForBeingAPalindrome()
{
while (FetchUserInputFromConsole() is string input
&& !string.IsNullOrWhiteSpace(input))
{
var isPalindrome = PalindromeFinder.IsPalindrome(input);
var modifier = isPalindrome ? "a" : "not a";
WriteLine($"It is {modifier} palindrome");
}
}
private static string FetchUserInputFromConsole()
{
Write("Enter a string: ");
return ReadLine();
}
}
}
I have a text file that a list of these words on it
Laptop
Laser
Macho
Sam
Samantha
Mulder
Microphone
Aardvark
And what I want to do is have user input type in a word and the console will basically respond with we have your word or we do not have your word. This is my code so far:
TextReader file = new StreamReader("Files/Exercise_Files/Words.txt");
Console.WriteLine("Welcome to FindWord");
string wordInput;
Console.WriteLine("Type in a word so we can try and find it: ");
wordInput = Console.ReadLine();
string sLine = file.ReadToEnd();
if (String.Compare(wordInput, sLine, true) == 0)
{
Console.WriteLine("We have found your word!");
}
else
{
Console.WriteLine("We have not found your word");
}
file.Dispose();
I have tried doing a couple of versions trying to solve this and one included adding a for-each loop but that confused me quite a bit. I'm not 100% sure when to use a for-each loop. I also want to have string comparison be case insensitive but the code I have now will always say word not found no matter what I input.
You can use the File.ReadAllLines() method to read the file lines into an array, and then the Linq extension method Contains to determine if a word exists in that list (and you can do a case-insensitive search):
static void Main(string[] args)
{
var filePath = #"c:\temp\temp.txt";
var words = File.ReadAllLines(filePath);
Console.Write("Enter a search term: ");
var searchTerm = Console.ReadLine();
if (words.Contains(searchTerm, StringComparer.OrdinalIgnoreCase))
{
Console.WriteLine("We have your word!");
}
else
{
Console.WriteLine("We do not have your word");
}
Console.ReadKey();
}
Load file into array
string[] words = File.ReadAllLines(path);
Then use LINQ to find
if (words.Any(w => string.Equals(w, input, StringComparison.InvariantCultureIgnoreCase)))
// do your thing here
Performance Contains vs Any
Contains is quicker but in this case difference will not be visible since searched collection is small.
public class Program
{
public static HashSet<string> _hs = new HashSet<String>(Enumerable.Range(1,1000).Select(x=> "Item " + x));
public static string[] _arr = Enumerable.Range(1,1000).Select(x=> "Item " + x).ToArray();
public static void Main()
{
var sw = new Stopwatch();
sw.Start();
bool f;
for (int i = 1; i < 1001; i++)
{
//f = _hs.Contains("Item " + i, StringComparer.OrdinalIgnoreCase);
f = _arr.Contains("Item " + i, StringComparer.OrdinalIgnoreCase);
}
Console.WriteLine(sw.Elapsed);
sw.Restart();
for (int i = 1; i < 1001; i++)
{
f = _hs.Any(w => string.Equals(w, "Item " + i, StringComparison.InvariantCultureIgnoreCase));
}
Console.WriteLine(sw.Elapsed);
}
}
String.Compare , compares two strings. I think, you may want to use Contains method. Please see below-
if (sLine.Contains(wordInput))
{
Console.WriteLine("We have found your word!");
}
else
{
Console.WriteLine("We have not found your word");
}
So I have a text box and on the text changed event I have the old text and the new text, and want to get the difference between them. In this case, I want to be able to recreate the new text with the old text using one remove function and one insert function. That is possible because there are a few possibilities of the change that was in the text box:
Text was only removed (one character or more using selection) - ABCD -> AD
Text was only added (one character or more using paste) - ABCD -> ABXXCD
Text was removed and added (by selecting text and entering text in the same action) - ABCD -> AXD
So I want to have these functions:
Sequence GetRemovedCharacters(string oldText, string newText)
{
}
Sequence GetAddedCharacters(string oldText, string newText)
{
}
My Sequence class:
public class Sequence
{
private int start;
private int end;
public Sequence(int start, int end)
{
StartIndex = start; EndIndex = end;
}
public int StartIndex { get { return start; } set { start = value; Length = end - start + 1; } }
public int EndIndex { get { return end; } set { end = value; Length = end - start + 1; } }
public int Length { get; private set; }
public override string ToString()
{
return "(" + StartIndex + ", " + EndIndex + ")";
}
public static bool operator ==(Sequence a, Sequence b)
{
if(IsNull(a) && IsNull(b))
return true;
else if(IsNull(a) || IsNull(b))
return false;
else
return a.StartIndex == b.StartIndex && a.EndIndex == b.EndIndex;
}
public override bool Equals(object obj)
{
return base.Equals(obj);
}
public static bool operator !=(Sequence a, Sequence b)
{
if(IsNull(a) && IsNull(b))
return false;
else if(IsNull(a) || IsNull(b))
return true;
else
return a.StartIndex != b.StartIndex && a.EndIndex != b.EndIndex;
}
public override int GetHashCode()
{
return base.GetHashCode();
}
static bool IsNull(Sequence sequence)
{
try
{
return sequence.Equals(null);
}
catch(NullReferenceException)
{
return true;
}
}
}
Extra Explanation: I want to know which characters were removed and which characters were added to the text in order to get the new text so I can recreate this. Let's say I have ABCD -> AXD. 'B' and 'C' would be the characters that were removed and 'X' would be the character that was added. So the output from the GetRemovedCharacters function would be (1, 2) and the output from the GetAddedCharacters function would be (1, 1). The output from the GetRemovedCharacters function refers to indexes in the old text and the output from the GetAddedCharacters function refers to indexes in the old text after removing the removed characters.
EDIT: I've thought of a few directions:
This code I created* which returns the sequence that was affected - if characters were removed it returns the sequence of the characters that were removed in the old text; if characters were added it returns the sequence of the characters that were added in the new text. It does not return the right value (which I myself not sure what I want it to be) when removing and adding text.
Maybe the SelectionStart property in the text box could help - the position of the caret after the text was changed.
*
private static Sequence GetChangeSequence(string oldText, string newText)
{
if(newText.Length > oldText.Length)
{
for(int i = 0; i < newText.Length; i++)
if(i == oldText.Length || newText[i] != oldText[i])
return new Sequence(i, i + (newText.Length - oldText.Length) - 1);
return null;
}
else if(newText.Length < oldText.Length)
{
for(int i = 0; i < oldText.Length; i++)
if(i == newText.Length || oldText[i] != newText[i])
return new Sequence(i, i + (oldText.Length - newText.Length) - 1);
return null;
}
else
return null;
}
Thanks.
A simple string comparison wont do the job since you are asking for a algorithm which supports added and removed chars at the same time and is hence not easy to achive in a few lines of code. Id suggest to use a library instead of writing your own comparison algorithm.
Have a look at this project for example.
I quickly threw this together to give you an idea of what I did to solve your question. It doesn't use your classes but it does find an index so it's customizable for you.
There are also obvious limitations to this as it is just bare bones.
This method will spot out changes made to the original string by comparing it to the changed string
// Find the changes made to a string
string StringDiff (string originalString, string changedString)
{
string diffString = "";
// Iterate over the original string
for (int i = 0; i < originalString.Length; i++)
{
// Get the character to search with
char diffChar = originalString[i];
// If found char in the changed string
if (FindInString(diffChar, changedString, out int index))
{
// Remove from the changed string at the index as we don't want to match to this char again
changedString = changedString.Remove(index, 1);
}
// If not found then this is a difference
else
{
// Add to diff string
diffString += diffChar;
}
}
return diffString;
}
This method will return true at the first matching occurrence (an obvious limitation but this is more to give you an idea)
// Find char at first occurence in string
bool FindInString (char c, string search, out int index)
{
index = -1;
// Iterate over search string
for (int i = 0; i < search.Length; i++)
{
// If found then return true with index
if (c == search[i])
{
index = i;
return true;
}
}
return false;
}
This is a simple helper method to show you an example
void SplitStrings(string oldStr, string newStr)
{
Console.WriteLine($"Old : {oldStr}, New: {newStr}");
Console.WriteLine("Removed - " + StringDiff(oldStr, newStr));
Console.WriteLine("Added - " + StringDiff(newStr, oldStr));
}
I've done it.
static void Main(string[] args)
{
while(true)
{
Console.WriteLine("Enter the Old Text");
string oldText = Console.ReadLine();
Console.WriteLine("Enter the New Text");
string newText = Console.ReadLine();
Console.WriteLine("Enter the Caret Position");
int caretPos = int.Parse(Console.ReadLine());
Sequence removed = GetRemovedCharacters(oldText, newText, caretPos);
if(removed != null)
oldText = oldText.Remove(removed.StartIndex, removed.Length);
Sequence added = GetAddedCharacters(oldText, newText, caretPos);
if(added != null)
oldText = oldText.Insert(added.StartIndex, newText.Substring(added.StartIndex, added.Length));
Console.WriteLine("Worked: " + (oldText == newText).ToString());
Console.ReadKey();
Console.Clear();
}
}
static Sequence GetRemovedCharacters(string oldText, string newText, int caretPosition)
{
int startIndex = GetStartIndex(oldText, newText);
if(startIndex != -1)
{
Sequence sequence = new Sequence(startIndex, caretPosition + (oldText.Length - newText.Length) - 1);
if(SequenceValid(sequence))
return sequence;
}
return null;
}
static Sequence GetAddedCharacters(string oldText, string newText, int caretPosition)
{
int startIndex = GetStartIndex(oldText, newText);
if(startIndex != -1)
{
Sequence sequence = new Sequence(GetStartIndex(oldText, newText), caretPosition - 1);
if(SequenceValid(sequence))
return sequence;
}
return null;
}
static int GetStartIndex(string oldText, string newText)
{
for(int i = 0; i < Math.Max(oldText.Length, newText.Length); i++)
if(i >= oldText.Length || i >= newText.Length || oldText[i] != newText[i])
return i;
return -1;
}
static bool SequenceValid(Sequence sequence)
{
return sequence.StartIndex >= 0 && sequence.EndIndex >= 0 && sequence.EndIndex >= sequence.StartIndex;
}
I wanted to count all of the "A's" in a paritcular string.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace TESTING
{
class Testing
{
static void Main(string[] args)
{
//ask user for the filename
string userInput = fetchFileName("Enter the textfile you want to view: ");
//test if the filename writes anything to console
string fileContents = File.ReadAllText(userInput);
string theFileContents = analyseFile(fileContents);
// Console.WriteLine(theFileContents);
Console.ReadLine();
}
private static string analyseFile(string fileContents)
{
string str = fileContents;
if (str.Contains("A"))
{
Console.WriteLine("YES");
}
else
{
Console.WriteLine("NO");
}
return str;
}
private static string fetchFileName(string askFileName)
{
Console.WriteLine(askFileName);
string userAnswer = Console.ReadLine();
return userAnswer;
}
}
}
Take a look at LINQ. It allows to perform whole range of operations on any kind of collection. And a string is a collection of chars. Below an example how LINQ can make your life easier:
string text = "A sdfsf a A sdfsf AAS sdfA";
int res = text.Count(letter => letter == 'A');
What happens here is that you take text and provide a predicat saying that you want to take any variable letter from the string such that the letter is equal to char A. Then you want to count them.
One of the easiest ways is to iterate over all characters in your file and check if the letter is equal to the letter you want.
When you realize that a string is nothing more then an array of characters, you can do something like this:
public int LetterCount(string filename, char letter)
{
int cnt = 0;
string source = File.ReadAllText(filename);
//Check every character in your string; if it matches increase the counter by 1
foreach (char c in source)
{
if(c == letter)
{
cnt++;
}
}
return cnt;
}
And use it like this:
int A_count = LetterCount(#"C:\test.txt", 'A');
Please note, that this code does not check, if the file actually exists. If you put in a wrong path, you end up with a FileNotFoundException.
Foreach is just another type of loop. This could just as easily be done with a for-loop. The trick is to split the string up in individual characters that you can later compare.
I'm sure you will figure out how to implement this if I just set you on the right path:
string test = "My name is Isak";
char[] arrayOfChars = test.ToCharArray();
int count = 0;
for (int i = 0; i < arrayOfChars.Length; i++)
{
if (arrayOfChars[i] == 'a' || arrayOfChars[i] == 'A')
{
count++;
}
}
try simple as
string test = "ABBCDABNDEAA";
int Count = test.Count(x => x == 'A');
Using LINQ, this can by really simple:
string myString = "ababsgsdfsaaaAA22bbaa";
var count = myString.ToLower().Count(c => c == 'a');
Console.Write(count);
Here we take the string and convert it to all lower case so that A and a will be counted together. Then we use the simple LINQ method Count() to count the number of a characters there are.
You could use linq
string text = "The quick brown fox jumps over the lazy dog";
var count = text.ToLower().Where(x => x == 'a').Count();
Console.WriteLine(count);
But if you cannot use any advanced techniques you could do it like this:
string text = "The quick brown fox jumps over the lazy dog";
int counter = 0;
for (int i = 0; i < text.Count(); i++)
{
if (text[i] == 'a' || text[i] == 'A')
{
counter++;
}
}
Console.WriteLine(counter);
You can do this:
string stringValue = "Addsadsd AAf,,werAA";
int qtdChar = stringValue.Count(x => x == 'A');
int qtdCharInsensitive = stringValue.Count(x => x == 'A' || x=='a');
If you do not want to use a foreach you could erase all the letter A's and compare the length difference.
A bit like this :
private static string analyseFile(string fileContents)
{
var strippedString = fileContents.Replace("A","");
var count = fileContents.Length - strippedString.Length;
return count.ToString();
}
I have a search method that takes in a user-entered string, splits it at each space character and then proceeds to find matches based on the list of separated terms:
string[] terms = searchTerms.ToLower().Trim().Split( ' ' );
Now I have been given a further requirement: to be able to search for phrases via double quote delimiters a la Google. So if the search terms provided were:
"a line of" text
The search would match occurrences of "a line of" and "text" rather than the four separate terms [the open and closing double quotes would also need to be removed before searching].
How can I achieve this in C#? I would assume regular expressions would be the way to go, but haven't dabbled in them much so don't know if they are the best solution.
If you need any more info, please ask. Thanks in advance for the help.
Here's a regex pattern that would return matches in groups named 'term':
("(?<term>[^"]+)"\s*|(?<term>[^ ]+)\s*)+
So for the input:
"a line" of text
The output items identified by the 'term' group would be:
a line
of
text
Regular expressions would definitely be the way to go...
You should check this MSDN link out for some info on the Regex class:
http://msdn.microsoft.com/en-us/library/system.text.regularexpressions.regex.aspx
and here is an excellent link to learn some regular expression syntax:
http://www.radsoftware.com.au/articles/regexlearnsyntax.aspx
Then to add some code examples, you could be doing it something along these lines:
string searchString = "a line of";
Match m = Regex.Match(textToSearch, searchString);
or if you just want to find out if the string contains a match or not:
bool success = Regex.Match(textToSearch, searchString).Success;
use the regular expression builder here
http://gskinner.com/RegExr/
and you will be able to manipulate the regular expression to how you need it displayed
Use Regexs....
string textToSearchIn = ""a line of" text";
string result = Regex.Match(textToSearchIn, "(?<=").*?(?=")").Value;
or if more then one, put this into a match collection...
MatchCollection allPhrases = Regex.Matches(textToSearchIn, "(?<=").*?(?=")");
The Knuth-Morris-Pratt (KMP algorithm)is recognised as the fastest algorithm for finding substrings in strings (well, technically not strings but byte-arrays).
using System.Collections.Generic;
namespace KMPSearch
{
public class KMPSearch
{
public static int NORESULT = -1;
private string _needle;
private string _haystack;
private int[] _jumpTable;
public KMPSearch(string haystack, string needle)
{
Haystack = haystack;
Needle = needle;
}
public void ComputeJumpTable()
{
//Fix if we are looking for just one character...
if (Needle.Length == 1)
{
JumpTable = new int[1] { -1 };
}
else
{
int needleLength = Needle.Length;
int i = 2;
int k = 0;
JumpTable = new int[needleLength];
JumpTable[0] = -1;
JumpTable[1] = 0;
while (i <= needleLength)
{
if (i == needleLength)
{
JumpTable[needleLength - 1] = k;
}
else if (Needle[k] == Needle[i])
{
k++;
JumpTable[i] = k;
}
else if (k > 0)
{
JumpTable[i - 1] = k;
k = 0;
}
i++;
}
}
}
public int[] MatchAll()
{
List<int> matches = new List<int>();
int offset = 0;
int needleLength = Needle.Length;
int m = Match(offset);
while (m != NORESULT)
{
matches.Add(m);
offset = m + needleLength;
m = Match(offset);
}
return matches.ToArray();
}
public int Match()
{
return Match(0);
}
public int Match(int offset)
{
ComputeJumpTable();
int haystackLength = Haystack.Length;
int needleLength = Needle.Length;
if ((offset >= haystackLength) || (needleLength > ( haystackLength - offset)))
return NORESULT;
int haystackIndex = offset;
int needleIndex = 0;
while (haystackIndex < haystackLength)
{
if (needleIndex >= needleLength)
return haystackIndex;
if (haystackIndex + needleIndex >= haystackLength)
return NORESULT;
if (Haystack[haystackIndex + needleIndex] == Needle[needleIndex])
{
needleIndex++;
}
else
{
//Naive solution
haystackIndex += needleIndex;
//Go back
if (needleIndex > 1)
{
//Index of the last matching character is needleIndex - 1!
haystackIndex -= JumpTable[needleIndex - 1];
needleIndex = JumpTable[needleIndex - 1];
}
else
haystackIndex -= JumpTable[needleIndex];
}
}
return NORESULT;
}
public string Needle
{
get { return _needle; }
set { _needle = value; }
}
public string Haystack
{
get { return _haystack; }
set { _haystack = value; }
}
public int[] JumpTable
{
get { return _jumpTable; }
set { _jumpTable = value; }
}
}
}
Usage :-
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
namespace KMPSearch
{
class Program
{
static void Main(string[] args)
{
if (args.Length != 2)
{
Console.WriteLine("Usage: " + Environment.GetCommandLineArgs()[0] + " haystack needle");
}
else
{
KMPSearch search = new KMPSearch(args[0], args[1]);
int[] matches = search.MatchAll();
foreach (int i in matches)
Console.WriteLine("Match found at position " + i+1);
}
}
}
}
Try this, It'll return an array for text. ex: { "a line of" text "notepad" }:
string textToSearch = "\"a line of\" text \" notepad\"";
MatchCollection allPhrases = Regex.Matches(textToSearch, "(?<=\").*?(?=\")");
var RegArray = allPhrases.Cast<Match>().ToArray();
output: {"a line of","text"," notepad" }