How many string2 exist in string1? - c#

I'm trying to find an algorithm that takes an input from user (string1) and then takes another (string2) then counts How many string2 exist in string1.
for example:
there is 2 # in string1 here
string1="##"
string2="#"
answer:2
there is 2 ## in string1:(1st one with the index of 0,1 and 2nd one with the index of 1,2)
string1="###"
string2="##"
answer=2
there is 3 ## in string1:(1st:index of 0,1 2nd:index of 1,2 3rd:index of 2,3)
string1="####"
string2="##"
answer=3
for counting # here we can simply do this:
string1.Length - string2.Length + 1
but I can only make the algorithm work for examples like these, while inputs can be anything. now i need an algorithm to do this for me.
Here is ,y code that works for my inputs, but doesn't work for all inputs.
for example if string2 was #a.
string string1 = "#abc##asd###12####";
string string2 = "##";
char[] str2 = string2.ToCharArray();
string[] str1 = string1.Split(str2);
string chars = "";
foreach (string s in str1)
foreach (char c in s)
chars += c;
//Result for chars are:a, b, c, a, s, d, 1, 2
string[] splits = string1.Split(chars.ToCharArray());
//Result for splits are:#, ##, ###, ####
int sum = 0;
for (int i = 0; i < splits.Length; i++)
{
if (splits[i].Length<string2.Length)
continue;
else
sum += splits[i].Length - string2.Length + 1;
}
Console.WriteLine(sum);
In my algorithm i seprated string1 by string2 characters and then count strings[] that was created by split method.
I already know that my algorithm is completely wrong, but I couldn't solve it anyway. I just put the code to show what i have tried.
if you write algorithm in your answer, that would be nice. I also have a little knowledge about lambda and linq so no problem if you could to this by lambda or linq or func or expression but explain about it.

Here's a working code :
string string1 = "#abc##asd###12####";
string string2 = "##";
List<int> indexes = new List<int>();
int index = -1;
while((index = string1.IndexOf(string2, index + 1)) >= 0)
{
indexes.Add(index);
}
Console.WriteLine(indexes.Count);

Related

Skipping a range of values in for loop C#

I'm trying to cycle through chars in a string.
string cycleMe = "Hi StackOverflow! Here is my string."
However, I want to skip over certain ranges of indexes. The ranges I want to skip over are stored in a List of objects, delims.
List<Delim> delims = delimCreator();
To retrieve each starting index and ending index for a range, I have to write a loop that accesses each "delim":
delims[0].getFirstIndex() //results in, say, index 2
delims[0].getLastIndex() //results in, say, index 4
delims[1].getFirstIndex() //results in, say, index 5
delims[1].getLastIndex() //results in, say, index 7
(there can be infinitely many "delim" objects in play)
If the above were my list, I'd want to print the string cycleMe, but skip all the chars between 2 and 4 (inclusive) and 5 and 7 (inclusive).
Expected output using the numbers above:
HiOverflow! Here is my string.
Here is the code I have written so far. It loops far more often than I'd expect (it loops ~x2 the number of characters in the string). Thanks in advance! =)
List<Delim> delims = delimAggregateInator(displayTextRaw);
for (int x = 0; x < cycleMe.Length;x++){
for (int i = 0; i < delims.Count; i++){
if (!(x >= delims[i].getFirstIndex() && x <= delims[i].getLastIndex())){
Debug.Log("test");
}
}
I assume that by skipping you meant you want to omit those characters from the original string. If that is the case, you can try Aggregate extension method like below.
string result = delims.Aggregate<Delim, string>(cycleMe, (str, d) => cycleMe = cycleMe.Remove(d.FirstIndex, (d.LastIndex - d.FirstIndex) + 1));
Make sure that the delim list is in the proper order.
Solution might be converting the string to char array, replacing the desired parts to spaces, and converting the output back to string.
Here is the modified version of your code:
string cycleMe = "Hi StackOverflow! Here is my string."
var charArray = cycleMe.ToCharArray(); // Converting to char array
List<Delim> delims = delimAggregateInator(displayTextRaw);
for (int x = 0; x < cycleMe.Length;x++){
for (int i = 0; i < delims.Count; i++){
// ORIGINAL: if (!(x >= delims[i].getFirstIndex() && x <= delims[i].getLastIndex())){
if (x >= delims[i].getFirstIndex() && x <= delims[i].getLastIndex()){
Debug.Log("test");
charArray[x] = ' '; // Replacing the item with space
}
}
string output = new string(charArray); // Converting back to string
P.S. This is probably not the most optimal solution but at least it should work.
You should use LINQ for that
struct Delim
{
public int First { get; set; }
public int Last { get; set; }
}
static void Main(string[] args)
{
string cycleMe = "Hi StackOverflow! Here is my string.";
var delimns = new List<Delim> { new Delim { First=2, Last=4}, new Delim { First = 5, Last = 7 } };
var cut = cycleMe.Where((c, i) =>
!delimns.Any(d => i >= d.First && i <= d.Last));
Console.WriteLine(new string(cut.ToArray());
}
That means I am basically only selecting letters, at positions which are not part of any cutting range.
Also: Fix your naming. A delimiter is a character, not a position (numeric)

C# Replacing Numbers With Symbols

I have an array where user inputs random characters, and i need to replace all numbers with symbol "*". And the worst thing is, that i cant use built in functions! If you can, help please!
Here if char.Number is build in function you should use numbers values from ASCII TABLE for the numbers.
string input = "ArrayWithR23andomChar44acter3sWit55hNumbersI6nIt";
char[] array = input.ToCharArray();
for(int i=0; i < array.Length; i++)
{
if (!char.IsNumber(input[i]))
continue;
array[i] = '*';
}
Here without char.IsNumber you can do it like this:
string input = "ArrayWithR23andomChar44acter3sWit55hNumbersI6nIt";
char[] array = input.ToCharArray();
for(int i=0; i < array.Length; i++)
{
if ((int)input[i] >= 48 && (int)input[i] <=57)
{
array[i] = '*';
}
}
Basically array of characters is nothing than string. You can use this regex to do the job done. For example:
string test = "dsad54dsads56dasd7a8s 5468sda";
Regex:
string t1 = Regex.Replace(test, "[0-9]+", "*");
or
string t1 = Regex.Replace(test, "[0-9]", "*");
The difference is that the first one will replace all consecutive numbers with just one *. The second one will replace every single number with *.
Or, if regex is considered as built in function you can use something like this:
char[] t2 = test.Select(c =>
{
if (c >= '0' && c <= '9')
{
return '*';
}
return c;
}).ToArray();

Using Substring to get digit before a string

I am reading a file in C#. I want to check value from a string. The line consists as following:
15 EMP_L_NAME HAPPENS 5 TIMES.
40 SUP HAPPENS 12 TIMES.
I want to find the number of times which is in the string before the string "TIMES". I have written the following code:
int arrayLength = 0;
int timesindex = line.IndexOf("TIMES");
if (timesindex > 0)
{
//Positon of the digit "5" in the first line
int indexCount = timesindex - 2;
if (int.TryParse(line.Substring(indexCount, 1), out occursCount))
{
arrayLength = occursCount;
}
}
Using the above code, I can find the number of "TIMES" for a single digigt number. But if it is a double digit, it won't work( e.g the second line). I have to develop a logic to find the digit which is separted by a space with "TIMES". How I can do that?
You can do:
Split your string on space and remove empty enteries.
Find Index of "TIMES."
Access element Index - 1
Like:
string str = "15 EMP_L_NAME HAPPENS 5 TIMES. ";
string[] array = str.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
int index = Array.IndexOf(array, "TIMES.");
int number;
if (!int.TryParse(array[index - 1], out number))
{
//invalid number
}
Console.WriteLine(number);
If the input is reliable you can do a quicky with String.Split()...
int arrayLength = 0;
int timesindex = line.IndexOf("TIMES");
if (timesindex > 0)
{
string[] items = line.Split(new char[] {' '}, StringSplitOptions.RemoveEmptyEntries);
if (int.TryParse(items[items.Length - 2], out occursCount))
{
arrayLength = occursCount;
}
}
This method relies on the desired number being the second from last "word" in each line
If your strings are always the same format, with exactly five words or "sections" or whatever you want to call them, you could use:
int times = 0;
Int32.TryParse(line.Split(' ')[3], out times);
This would have to be more robust there's a chance the number may not exist in the string, or the string is in a completely different format.
Look at LastIndexOf combined with your timesindex. You can look for the space before the space before (timesindex-1), and then you have the two positions around the number.
int timesindex = line.IndexOf("TIMES");
int firstSpace = line.LastIndexOf(" ", timesindex-1);
string number = line.Substring(firstSpace, timesindex-firstSpace);
Though this might need some adjustments on the indexes, but that's the idea anyway
Try this
int timesindex = line.IndexOf("TIMES");
int happensindex = line.IndexOf("HAPPENS") + 7; //Add 7 cause HAPPEND is 7 chars long
if (timesindex > 0)
{
//Positon of the digit "5" in the first line
if (int.TryParse(line.Substring(happensindex, timesindex).trim(), out occursCount))
{
arrayLength = occursCount;
}
}
A Regex would be cleaner:
var regex = new Regex(#"(\d+)\sTIMES"); // match a number followed by whitespace then "TIMES"
string num = regex.Match(" 15 EMP_L_NAME HAPPENS 5 TIMES").Groups[1].ToString();
int val = int.Parse(num);
Using LINQ:
string[] lines = {"15 EMP_L_NAME HAPPENS 5,1 TIMES.", "40 SUP HAPPENS 12 TIMES. "};
var allValues = lines.Select(line =>
{
double temp;
var words = line.Split(new char[] {' '}, StringSplitOptions.RemoveEmptyEntries);
var value = words[Array.IndexOf(words,"TIMES.") - 1];
if (double.TryParse(value, out temp)) return temp;
else return 0;
}).ToList();
foreach (var value in allValues)
{
Console.WriteLine(value);
}
// Output:
// 5,1
// 12
You can use System.Text.RegularExpressions.Regex, i.e. a regular expression, in order to find a pattern in a string:
string input = "40 SUP HAPPENS 12 TIMES.";
Match match = Regex.Match(input, #"(?<=HAPPENS\s)\d+(?=\sTIMES)");
if (match.Success) {
Console.WriteLine(match.Value); '==> "12"
}
Explanation of the regular expression: It uses the general pattern (?<=prefix)find(?=suffix) in order to find a position between a prefix and suffix.
(?<=HAPPENS\s) Prefix consisting of "HAPPENS" plus a whitespace (\s)
\d+ A digit (\d) repeated one or more times (+)
(?=\sTIMES) Suffix consisting of a whitespace (\s) plus "TIMES"
If you only want to test for "TIMES" but not for "HAPPENS", you can just drop the first part:
Match match = Regex.Match(input, #"\d+(?=\sTIMES)");
Since you are using the same search pattern many times, it is advisable to create a Regex once instead of calling a static method:
Regex regex = new Regex(#"\d+(?=\sTIMES)");
// Use many times with different inputs
Match match = regex.Match(input);

Masking all characters of a string except for the last n characters

I want to know how can I replace a character of a string with condition of "except last number characters"?
Example:
string = "4111111111111111";
And I want to make it that
new_string = "XXXXXXXXXXXXX1111"
In this example I replace the character to "X" except the last 4 characters.
How can I possibly achieve this?
Would that suit you?
var input = "4111111111111111";
var length = input.Length;
var result = new String('X', length - 4) + input.Substring(length - 4);
Console.WriteLine(result);
// Ouput: XXXXXXXXXXXX1111
How about something like...
new_string = new String('X', YourString.Length - 4)
+ YourString.Substring(YourString.Length - 4);
create a new string based on the length of the current string -4 and just have it all "X"s. Then add on the last 4 characters of the original string
Here's a way to think through it. Call the last number characters to leave n:
How many characters will be replaced by X? The length of the string minus n.
How can we replace characters with other characters? You can't directly modify a string, but you can build a new one.
How to get the last n characters from the original string? There's a couple ways to do this, but the simplest is probably Substring, which allows us to grab part of a string by specifying the starting point and optionally the ending point.
So it would look something like this (where n is the number of characters to leave from the original, and str is the original string - string can't be the name of your variable because it's a reserved keyword):
// 2. Start with a blank string
var new_string = "";
// 1. Replace first Length - n characters with X
for (var i = 0; i < str.Length - n; i++)
new_string += "X";
// 3. Add in the last n characters from original string.
new_string += str.Substring(str.Length - n);
This might be a little Overkill for your ask. But here is a quick extension method that does this.
it defaults to using x as the masking Char but can be changed with an optional char
public static class Masking
{
public static string MaskAllButLast(this string input, int charsToDisplay, char maskingChar = 'x')
{
int charsToMask = input.Length - charsToDisplay;
return charsToMask > 0 ? $"{new string(maskingChar, charsToMask)}{input.Substring(charsToMask)}" : input;
}
}
Here a unit tests to prove it works
using Xunit;
namespace Tests
{
public class MaskingTest
{
[Theory]
[InlineData("ThisIsATest", 4, 'x', "xxxxxxxTest")]
[InlineData("Test", 4, null, "Test")]
[InlineData("ThisIsATest", 4, '*', "*******Test")]
[InlineData("Test", 16, 'x', "Test")]
[InlineData("Test", 0, 'y', "yyyy")]
public void Testing_Masking(string input, int charToDisplay, char maskingChar, string expected)
{
//Act
string actual = input.MaskAllButLast(charToDisplay, maskingChar);
//Assert
Assert.Equal(expected, actual);
}
}
}
StringBuilder sb = new StringBuilder();
Char[] stringChar = string.toCharArray();
for(int x = 0; x < stringChar.length-4; x++){
sb.append(stringChar[x]);
}
sb.append(string.substring(string.length()-4));
string = sb.toString();
I guess you could use Select with index
string input = "4111111111111111";
string new_string = new string(input.Select((c, i) => i < input.Length - 4 ? 'X' : c).ToArray());
Some of the other concise answers here did not account for strings less than n characters. Here's my take:
var length = input.Length;
input = length > 4 ? new String('*', length - 4) + input.Substring(length - 4) : input;
lui,
Please Try this one...
string dispString = DisplayString("4111111111111111", 4);
Create One function with pass original string and no of digit.
public string DisplayString(string strOriginal,int lastDigit)
{
string strResult = new String('X', strOriginal.Length - lastDigit) + strOriginal.Substring(strOriginal.Length - lastDigit);
return strResult;
}
May be help you....
Try this:
String maskedString = "...."+ (testString.substring(testString.length() - 4, testString.length()));
Late to the party but I also wanted to mask all but the last 'x' characters, but only mask numbers or letters so that any - ( ), other formatting, etc would still be shown. Here's my quick extension method that does this - hopefully it helps someone. I started with the example from Luke Hammer, then changed the guts to fit my needs.
public static string MaskOnlyChars(this string input, int charsToDisplay, char maskingChar = 'x')
{
StringBuilder sbOutput = new StringBuilder();
int intMaskCount = input.Length - charsToDisplay;
if (intMaskCount > 0) //only mask if string is longer than requested unmasked chars
{
for (var intloop = 0; intloop < input.Length; intloop++)
{
char charCurr = Char.Parse(input.Substring(intloop, 1));
byte[] charByte = Encoding.ASCII.GetBytes(charCurr.ToString());
int intCurrAscii = charByte[0];
if (intloop <= (intMaskCount - 1))
{
switch (intCurrAscii)
{
case int n when (n >= 48 && n <= 57):
//0-9
sbOutput.Append(maskingChar);
break;
case int n when (n >= 65 && n <= 90):
//A-Z
sbOutput.Append(maskingChar);
break;
case int n when (n >= 97 && n <= 122):
//a-z
sbOutput.Append(maskingChar);
break;
default:
//Leave other characters unmasked
sbOutput.Append(charCurr);
break;
}
}
else
{
//Characters at end to remain unmasked
sbOutput.Append(charCurr);
}
}
}
else
{
//if not enough characters to mask, show unaltered input
return input;
}
return sbOutput.ToString();
}

Split a long string into an array of shorter strings

How can I split a string of around 300 (n) words into an array of n/30 strings of 30 words?
You can use Regex.Matches:
string[] bits = Regex.Matches(input, #"\w+(?:\W+\w+){0,29}")
.Cast<Match>()
.Select(match => match.Value)
.ToArray();
See it working online: ideone
A Regex split would make sense if you have a very large or a very small of characters that can be a part of your string. Alternatively, you can use the Substring method of the String class to get the desired result:
string input = "abcdefghijklmnopqrstuvwxyz";
const int INTERVAL = 5;
List<string> lst = new List<string>();
int i = 0;
while (i < input.Length)
{
string sub = input.Substring(i, i + INTERVAL < input.Length ? INTERVAL : input.Length - i);
Console.WriteLine(sub);
lst.Add(sub);
i += INTERVAL;
}

Categories