Lets suppose i have two strings string1 and string2.
var string1 = "images of canadian geese goslings";
var string2 = "Canadian geese with goslings pictures to choose from, with no signup needed";
I need to find biggest substring of string1 which matches in string2.
here biggest substring will be "canadian geese" which is matching in string2.
How can I find it? I tried breaking string1 into char[] and find words then merged matched words but that failed my objective.
classy loop approach - the result includes te space after geese "canadian geese "
var string1 = "images of canadian geese goslings";
var string2 = "Canadian geese with goslings pictures to choose from, with no signup needed";
string result = "";
for (int i = 0; i < string1.Length; i++)
{
for (int j = 0; j < string1.Length - i; j++)
{
//add .Trim() here if you want to ignore space characters
string searchpattern = string1.Substring(i, j);
if (string2.IndexOf(searchpattern, StringComparison.OrdinalIgnoreCase) > -1 && searchpattern.Length > result.Length)
{
result = searchpattern;
}
}
}
https://dotnetfiddle.net/q3rHjI
Side note:
canadian and Canadian are not equal so you have to use StringComparison.OrdinalIgnoreCase if you want to search case insensitive
Have a look at the following code https://dotnetfiddle.net/aPyw3o
public class Program {
static IEnumerable<string> substrings(string s, int length) {
for (int i = 0 ; i + length <= s.Length; i++) {
var ss = s.Substring(i, length);
if (!(ss.StartsWith(" ") || ss.EndsWith(" ")))
yield return ss;
}
}
public static void Main()
{
int count = 0;
var string1 = "images of canadian geese goslings";
var string2 = "Canadian geese with goslings pictures to choose from, with no signup needed";
string result = null;
for (int i = string1.Length; i>0 && string.IsNullOrEmpty(result); i--) {
foreach (string s in substrings(string1, i)) {
count++;
if (string2.IndexOf(s, StringComparison.CurrentCultureIgnoreCase) >= 0) {
result = s;
break;
}
}
}
if (string.IsNullOrEmpty(result))
Console.WriteLine("no common substrings found");
else
Console.WriteLine("'" + result + "'");
Console.WriteLine(count);
}
}
The substrings method returns all substrings of the string s with the length of length (for the yield have a look at the documentation https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/yield) We skip substrings that start or end with a space, as we don't want whitespaces to make a substring longer than it really is)
The outer loop iterates through all the possible length values for the substrings, from the longest (ie string1.Length) to the shortest (ie 1). Then for each of the found substrings of length i is checked, if it's also a substring of string2. If that's the case, we can stop, as there cannot be any longer common substring, because we checked all longer substrings in previous iterations. But of course there may be other common substrings with length i
I'm going to add one more, using span/readonlymemory so you can avoid allocating all the strings that the current answers create. Note I didn't do any check for starting space or ending space as that does not seem to be a requirement for the question. This does do a case insensitive search, if you don't want that you can make it more efficient by using the built in indexof and dropping the case insensitive compares.
static void Main(string[] _)
{
var string1 = "images of canadian geese goslings";
var string2 = "Canadian geese with goslings pictures to choose from, with no signup needed";
var longest = FindLongestMatchingSubstring(string1, string2);
Console.WriteLine(longest);
}
static string FindLongestMatchingSubstring(string lhs, string rhs)
{
var left = lhs.AsMemory();
var right = rhs.AsMemory();
ReadOnlyMemory<char> longest = ReadOnlyMemory<char>.Empty;
for (int i = 0; i < left.Length; ++i)
{
foreach (var block in FindMatchingSubSpans(left, i, right))
{
if (block.Length > longest.Length)
longest = block;
}
}
if (longest.IsEmpty)
return string.Empty;
return longest.ToString();
}
static IEnumerable<ReadOnlyMemory<char>> FindMatchingSubSpans(ReadOnlyMemory<char> source, int pos, ReadOnlyMemory<char> matchFrom)
{
int lastMatch = 0;
for (int i = pos; i < source.Length; ++i)
{
var ch = source.Span[i];
int match = IndexOfChar(matchFrom, lastMatch, ch);
if (-1 != match)
{
lastMatch = match + 1;
int end = i;
while (++end < source.Length && ++match < matchFrom.Length)
{
char lhs = source.Span[end];
char rhs = matchFrom.Span[match];
if (lhs != rhs && lhs != (char.IsUpper(rhs) ? char.ToLower(rhs) : char.ToUpper(rhs)))
{
break;
}
}
yield return source.Slice(i, end - i);
}
}
}
static int IndexOfChar(ReadOnlyMemory<char> source, int pos, char ch)
{
char alt = char.IsUpper(ch) ? char.ToLower(ch) : char.ToUpper(ch);
for (int i = pos; i < source.Length; ++i)
{
char m = source.Span[i];
if (m == ch || m == alt)
return i;
}
return -1;
}
Related
I am trying to see weather the string is in alphabetical order or no and this error pops up
System.ArgumentOutOfRangeException: Index and length must refer to a location within the string.
Parameter name: length
at System.String.Substring(Int32 startIndex, Int32 length)
at Rextester.Program.Main(String[] args)**
public static void Main(string[] args)
{
string str = "bat\ncat\ndog\n";
int c = 0;
for (int i = 0; i < str.Length; i++)
{
if ((str.Substring(i,i + 1).Equals("\n")))
{
c++;
}
}
String[] strArray = new String[c + 1]; //declare with size
int g = 0;
String h = "";
for (int i = 0; i < str.Length; i++)
{
if ((str.Substring(i,i + 1).Equals("\n")))
{
strArray[g] = h;
h = "";
g = g + 1;
}
else
{
h = h + str.Substring(i,i + 1);
}
}
String p = "True";
for (int i = 0; i < g; i++)
{
if (i < (g - 1))
{
String f = strArray[i];
String g2 = strArray[i + 1];
char d = f[0];
char s = g2[0];
int d1 = (int)d;
int s1 = (int)s;
if (d1 > s1)
{
p = "False";
}
}
}
Console.WriteLine(p);
}
}
Not sure about what you are doing in your second loop and why is it so complex. We can do the same like this. Hope this helps.
using System;
public class Program
{
public static void Main()
{
string str = "abcd";
str = str.Replace('\n',' ');
String p = "True";
for (int i = 1; i < str.Length; i++) {
// if element at index 'i' is less
// than the element at index 'i-1'
// then the string is not sorted
if (str[i] < str[i - 1]) {
p = "false";
}
}
Console.WriteLine(p);
}
}
Pay attention to the definition of substring
The substring starts at a specified character position and has a
specified length
Considering your first use of substring, here
for (int i = 0; i < str.Length; i++)
{
if (str.Substring(i, i + 1).Equals("\n"))
{
c++;
}
}
What happens when we get to i=6 here? Substring tries to give you a new string that starts at position i = 6, and is length = 7 characters long. So it tries to give you 7 characters starting from str[6] to str[12]. Well, there is no str[12], so you get an exception.
Its clear that your intent is NOT to get a string that starts at position 6 and is 7 characters long. You want ONE character, so your loop should be this
for (int i = 0; i < str.Length; i++)
{
if (str.Substring(i, 1).Equals("\n"))
{
c++;
}
}
But theres a much simpler way to get your words in alphabetical order using LINQ
string str = "bat\ncat\ndog\n";
//Removes the trailing \n so you don't have one entry that is only whitespace
str = str.Trim();
string[] strSplit = str.Split('\n').OrderBy(x => x[0]).ToArray();
Now all substrings are sorted alphabetically and you can do whatever you want with them
I've seen few implementations of variations of string in C#, but none of them had any limitation on their length. Unfortunately, I cannot modify them to achieve my goal which is e.g.
for:
string = "ABCD" and variationLength = 2
generate new strings:
AB, AC, AD, BA, BC, BD, CA, CB, CD, DA, DB, DC
I'm looking for exactly this Python's itertools.permutations implementation but in C#. (https://docs.python.org/3/library/itertools.html#itertools.permutations)
Is there anything similar to its in C#? If not, then what is the easiest way to implement it?
Edit_2:
so far I came up with an idea to list all unique chars of given string and then get variations out of them
static void PrintAllKLengthPerm(string str, int k)
{
int n = str.Length;
PrintAllKLengthPermRec(str, "", n, k);
}
// The main recursive method to print all possible strings of length k
static void PrintAllKLengthPermRec(string str, String prefix, int n, int k)
{
// Base case: k is 0, print prefix
if (k == 0)
{
Console.WriteLine(prefix);
return;
}
// One by one add all characters from str and recursively
// call for k equals to k-1
for (int i = 0; i < n; ++i)
{
// Next character of input added
String newPrefix = prefix + str[i];
// k is decreased, because we have added a new character
PrintAllKLengthPermRec(str, newPrefix, n, k - 1);
}
}
static void Main(string[] args)
{
string str = "ABCD";
int permLen = 2;
//get all unique characters in string
string uniqStr = new String(str.Distinct().ToArray());
// Print all possible strings of length permLen out of uniqStr characters
PrintAllKLengthPerm(uniqStr, permLen);
}
However I am looking for more optimal and effective solution
Here's a truly recursive permutation method:
public IEnumerable<string> Permutate(string source, int count)
{
if (source.Length == 1)
{
yield return source;
}
else if (count == 1)
{
for (var n = 0; n < source.Length; n++)
{
yield return source.Substring(n, 1);
}
}
else
{
for (var n = 0; n < source.Length; n++)
foreach (var suffix in Permutate(
source.Substring(0, n)
+ source.Substring(n + 1, source.Length - n - 1), count -1))
{
yield return source.Substring(n, 1) + suffix;
}
}
}
It can be called with Permutate("ABCD", 2) and returns this:
I made the following recursive function which accomplishes your task:
static void Permutations(List<string> output, string str, int n, string curr)
{
if(curr.Length == n)
{
output.Add(curr);
return;
}
foreach(char c in str)
if(!curr.Contains(c.ToString()))
Permutations(output, str, n, curr + c.ToString());
}
and then you call it like this:
string str = "ABCD";
int length = 2;
List<string> perms = new List<string>();
Permutations(perms, str, length, "");
// now the list "perms" will contain the permutations of "str" in length "n"
List<string> newPermutations = new List<string>();
for(int a = 0; a!=inString.Count; a++)
for((int b = 0; b!=inString.Count; b++)
if(noRepetitions && a == b) continue;
newPermutations.Add(""+inString[a] + inString[b]);
I think that that should work; I am still trying to figure out a way to not only have 2 letters.
Edit: Edited it to work, the old one just didn't work... lol
Edit: Thanks to #Bloopy, they helped me spot some errors in my for loops
Here's a solution using modulo and division. There are 4² possible strings of length 2 using the letters ABCD. Number them from 0 to 4²-1 and repeatedly divide each number by 4. Use the resulting remainders as array indexes on the ABCD string.
This has the advantage of allowing you to keep the strings with repeated elements (AA, BB, CC, DD) when needed – just skip the discard step.
string alphabet = "ABCD";
int length = 2;
int[] indexes = new int[length];
char[] item = new char[length];
// loop through all possible strings for the given alphabet and length
for (int i = 0; i < Math.Pow(alphabet.Length, length); i++) {
int dividend = i;
for (int j = length - 1; j >= 0; j--) {
indexes[j] = dividend % alphabet.Length;
dividend /= alphabet.Length;
}
// discard any that use the same alphabet element more than once
if (indexes.Distinct().Count() < length)
continue;
for (int k = 0; k < length; k++) {
item[k] = alphabet[indexes[k]];
}
Console.WriteLine(item);
}
Alternatively, here's a really brief solution using LINQ. Note that this one doesn't work correctly if there are duplicate elements in the string (unless you want to remove the call to Where and keep the AA, BB etc.). I'd need to track the indexes like I did in my method above.
IEnumerable<string> prm = alphabet.Select(c => c.ToString());
for (int a = 1; a < length; a++)
prm = prm.SelectMany(s => alphabet.Where(t => !s.Contains(t)), (x, y) => x + y);
foreach (string s in prm)
Console.WriteLine(s);
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 6 years ago.
Improve this question
How can I ignore characters between /* */ in string when copying to another string?
string str1 = "/*TODO:if*/";
How to ignore the caracters between /**/ so the new string will look like this:
string str2 = "/**/";
I am not allowed to use any library functions!
string str2 = Regex.Replace(str1, #"/\*.*\*/", "/**/");
Using a regular expression, you can capture all instances of /*[anything]*/ and replace it with just the text you want: /**/. However, this will be very greedy. If you have the string /*foo*/bar/*baz*/, this will eat all of it.
string str2 = Regex.Replace(str1, #"/\*.+?\*/", "/**/");
By changing it to be a lazy regex, the string /**/bar/**/ will be returned.
Given the edit above, this could also be done without Regex by doing a simple index search - though it is a greedy replacement.
string str2 = str1.Substring(0, str1.IndexOf("/*")) + "/*" + str1.Substring(str1.LastIndexOf("*/"));
This just takes everything before the first /* and then everything after the last */.
Try this code (it does not use any library function):
static string FormatString(string str) =>
RemoveAfter(str, "/*") + SubstringFrom(str, "*/");
static int IndexOf(string str, string value)
{
for (int i = 0; i < str.Length - value.Length; i++)
{
bool found = true;
for (int j = 0; j < value.Length; j++)
{
if (str[i + j] != value[j])
{
found = false;
break;
}
}
if (found)
{
return i;
}
}
return -1;
}
static int LastIndexOf(string str, string value)
{
for (int i = str.Length - value.Length; i >= 0; i--)
{
bool found = true;
for (int j = 0; j < value.Length; j++)
{
if (str[i + j] != value[j])
{
found = false;
break;
}
}
if (found)
{
return i;
}
}
return -1;
}
static string SubstringFrom(string str, string value)
{
int startIndex = LastIndexOf(str, value);
int length = str.Length - startIndex;
char[] result = new char[length];
for (int i = 0; i < length; i++)
{
result[i] = str[startIndex + i];
}
return new string(result);
}
static string RemoveAfter(string str, string value)
{
int length = IndexOf(str, value) + value.Length;
char[] result = new char[length];
for (int i = 0; i < length; i++)
{
result[i] = str[i];
}
return new string(result);
}
I'm not sure it makes sense that you can't use library functions, considering all functions are essentially library functions. I think the limitation here is that you can't bring in a library that doesn't already come imported in a new project. That's OK, we can do this hobbled like that. The Type string has a Split function, and failing that we can play it dirty and use indeces like it's 1995. I didn't get to test these but you should be well on your way with them. It was a fun little exercise, honestly.
Given : string str1 = "Stufftokeep/*TODO:if*/StufftokeepAgain";
string[] crazyHomework = str1.Split('/');
string result = string.Empty;
foreach(string s in crazyHomework)
{
if(s.IndexOf('*') == -1)
result += s + " "; //added a space to keep them separate
}
That gets you there using only System functions. Failing that, you can mutate the string into a lovely array of type char (which is all a string is anyway).
string result = string.Empty;
bool copy = true;
char[] array = str1.ToCharArray()
foreach(char a in array)
{
int i = array.IndexOf[a];
if(a == "/" && array.IndexOf(a) != array.Length - 1
&&
(array[a + 1] == '*' || array[a -1] == '*'))
{
copy = !copy;
}
if(copy)
result += a.ToString();
}
You'll have some space issues on that one if there isn't whitespace in the string, though.
Quick and dirty
string temp = null;
string str1 = "this shoudl remain/*TODO:if*/*/*testing again */-and so should this";
int x, y;
while ((x = str1.IndexOf("/*")) != -1)
{
if ((y = str1.IndexOf("*/")) > x)
{
temp += str1.Substring(0, x + 2) + str1.Substring(y, 2);
str1 = str1.Substring(y + 2);
continue;
}
temp += str1.Substring(y, x);
str1 = str1.Substring(x)
}
temp += str1;
I am a beginner in C# and i am trying to make a "hangman" game. I got stuck at the process when the player guess a letter.
If the word for example is DATA, the application only gets the first A in DATA.
I understand that i have to loop the word to get all the A´s but i am having touble with making it work!
here is my code for the method myGuess:
public void myGuess(String letter)
{
int plats = 0;
string wordToGuess = label4.Text;
plats = wordToGuess.IndexOf(letter);
string wordToShow = label5.Text;
//ersätt "_" med bokstaven på alla positioner bokstaven dyker upp
wordToShow = wordToShow.Substring(0, wordToGuess.IndexOf(letter)) + letter +
wordToShow.Substring(plats + 1, wordToShow.Length - (plats + 1));
label5.Text = wordToShow;
}
I have been trying to google it but because i am a beginner i don't understand the
suggestions people give. Hopefully it is a way to loop for more than one letter with IndexOf?
IndexOf returns the index of the first instance of the character in the string. You could manipulate your string using substring, but you'd be making it more complicated than you need to need. Instead, you can just loop through each of the characters in the String with a for loop:
for (int i = 0; i < wordToGuess.Length; i++ )
{
if (WordToGuess[i] == letter)
{
//Update the correctly guessed letters, (using value of i to determine which letter to make visible.)
}
}
label5.Text = wordToShow;
You can use this:
label4(wordToGuess): DATA
label5(wordToShow): ****
When you call myGuess('A')
label4(wordToGuess): DATA
label5(wordToShow): *A*A
When you call myGuess('T')
label4(wordToGuess): DATA
label5(wordToShow): *ATA
...
public void myGuess(char letter)
{
string wordToGuess = label4.Text;
string wordToShow = label5.Text;
if (wordToShow.Length == 0)
{
for (int i = 0; i < wordToGuess.Length; i++)
wordToShow += "*";
}
for (int i = 0; i < wordToGuess.Length; i++)
{
if (wordToGuess[i] == letter || wordToGuess[i] == wordToShow[i])
wordToShow = wordToShow.Remove(i,1).Insert(i, Char.ToString(letter));
}
label5.Text = wordToShow;
}
Here's a long solution that's probably overly generic.
List<int> findIndexes(string myStr, char letter)
{
var foundIndexes = new List<int>();
for (int i = 0; i < myStr.Length; i++)
{
if (myStr[i] == letter)
foundIndexes.Add(i);
}
return foundIndexes;
}
string ReplaceIndex(string s, int index, char letter){
return s.Substring(0, index )
+ letter
+ s.Substring(index + 1, s.Length - (index + 1));
}
void Main()
{
string s= "data";
string wordToShow = "____";
var letter = 'a';
var indexes = findIndexes(s, letter);
foreach (var index in indexes)
{
wordToShow = ReplaceIndex(wordToShow, index, letter);
}
Console.WriteLine (wordToShow);
}
A simple for loop should handle it.
for (int i = 0; i < wordToGuess.Length; i++)
{
if (wordToGuess[i].ToString().Equals(letter.ToString(), System.StringComparison.InvariantCultureIgnoreCase))
{
wordToShow = string.Format("{0}{1}{2}", wordToShow.Substring(0, i), letter, wordToShow.Substring(i, wordToShow.Length - (i + 1)));
}
}
Here's a fiddle: http://dotnetfiddle.net/UATeVJ
I have a long string and I want to fit that in a small field. To achieve that, I break the string into lines on whitespace. The algorithm goes like this:
public static string BreakLine(string text, int maxCharsInLine)
{
int charsInLine = 0;
StringBuilder builder = new StringBuilder();
for (int i = 0; i < text.Length; i++)
{
char c = text[i];
builder.Append(c);
charsInLine++;
if (charsInLine >= maxCharsInLine && char.IsWhiteSpace(c))
{
builder.AppendLine();
charsInLine = 0;
}
}
return builder.ToString();
}
But this breaks when there's a short word, followed by a longer word. "foo howcomputerwork" with a max length of 16 doesn't break, but I want it to. One thought I has was looking forward to see where the next whitespace occurs, but I'm not sure whether that would result in the fewest lines possible.
Enjoy!
public static string SplitToLines(string text, char[] splitOnCharacters, int maxStringLength)
{
var sb = new StringBuilder();
var index = 0;
while (text.Length > index)
{
// start a new line, unless we've just started
if (index != 0)
sb.AppendLine();
// get the next substring, else the rest of the string if remainder is shorter than `maxStringLength`
var splitAt = index + maxStringLength <= text.Length
? text.Substring(index, maxStringLength).LastIndexOfAny(splitOnCharacters)
: text.Length - index;
// if can't find split location, take `maxStringLength` characters
splitAt = (splitAt == -1) ? maxStringLength : splitAt;
// add result to collection & increment index
sb.Append(text.Substring(index, splitAt).Trim());
index += splitAt;
}
return sb.ToString();
}
Note that splitOnCharacters and maxStringLength could be saved in user settings area of the app.
Check the contents of the character before writing to the string builder and or it with the current count:
public static string BreakLine(string text, int maxCharsInLine)
{
int charsInLine = 0;
StringBuilder builder = new StringBuilder();
for (int i = 0; i < text.Length; i++)
{
char c = text[i];
if (char.IsWhiteSpace(c) || charsInLine >= maxCharsInLine)
{
builder.AppendLine();
charsInLine = 0;
}
else
{
builder.Append(c);
charsInLine++;
}
}
return builder.ToString();
}
update a code a bit, the #dead.rabit goes to loop sometime.
public static string SplitToLines(string text,char[] splitanyOf, int maxStringLength)
{
var sb = new System.Text.StringBuilder();
var index = 0;
var loop = 0;
while (text.Length > index)
{
// start a new line, unless we've just started
if (loop != 0)
{
sb.AppendLine();
}
// get the next substring, else the rest of the string if remainder is shorter than `maxStringLength`
var splitAt = 0;
if (index + maxStringLength <= text.Length)
{
splitAt = text.Substring(index, maxStringLength).LastIndexOfAny(splitanyOf);
}
else
{
splitAt = text.Length - index;
}
// if can't find split location, take `maxStringLength` characters
if (splitAt == -1 || splitAt == 0)
{
splitAt = text.IndexOfAny(splitanyOf, maxStringLength);
}
// add result to collection & increment index
sb.Append(text.Substring(index, splitAt).Trim());
if(text.Length > splitAt)
{
text = text.Substring(splitAt + 1).Trim();
}
else
{
text = string.Empty;
}
loop = loop + 1;
}
return sb.ToString();
}