Take only letters from the string and reverse them - c#

I'm preparing for my interview, faced the problem with the task. The case is that we're having a string:
test12pop90java989python
I need to return new string where words will be reversed and numbers will stay in the same place:
test12pop90java989python ==> tset12pop90avaj989nohtyp
What I started with:
Transferring string to char array
Use for loop + Char.IsNumber
??
var charArray = test.ToCharArray();
for (int i = 0; i < charArray.Length; i++)
{
if (!Char.IsNumber(charArray[i]))
{
....
}
}
but currently I'm stuck and don't know how to proceed, any tips how it can be done?

You can't reverse a run of letters until you've observed the entire run; until then, you need to keep track of the pending letters to be reversed and appended to the final output upon encountering a number or the end of the string. By storing these pending characters in a Stack<> they are naturally returned in the reverse order they were added.
static string Transform(string input)
{
StringBuilder outputBuilder = new StringBuilder(input.Length);
Stack<char> pending = new Stack<char>();
foreach (char c in input)
if (char.IsNumber(c))
{
// In the reverse order of which they were added, consume
// and append pending characters as long as they are available
while (pending.Count > 0)
outputBuilder.Append(pending.Pop());
// Alternatively...
//foreach (char p in pending)
// outputBuilder.Append(p);
//pending.Clear();
outputBuilder.Append(c);
}
else
pending.Push(c);
// Handle pending characters when input does not end with a number
while (pending.Count > 0)
outputBuilder.Append(pending.Pop());
return outputBuilder.ToString();
}
A similar but buffer-free way is to do it is to store the index of the start of the current run of letters, then walk back through and append each character when a number is found...
static string Transform(string input)
{
StringBuilder outputBuilder = new StringBuilder(input.Length);
int lettersStartIndex = -1;
for (int i = 0; i < input.Length; i++)
{
char c = input[i];
if (char.IsNumber(c))
{
if (lettersStartIndex >= 0)
{
// Iterate backwards from the previous character to the start of the run
for (int j = i - 1; j >= lettersStartIndex; j--)
outputBuilder.Append(input[j]);
lettersStartIndex = -1;
}
outputBuilder.Append(c);
}
else if (lettersStartIndex < 0)
lettersStartIndex = i;
}
// Handle remaining characters when input does not end with a number
if (lettersStartIndex >= 0)
for (int j = input.Length - 1; j >= lettersStartIndex; j--)
outputBuilder.Append(input[j]);
return outputBuilder.ToString();
}
For both implementations, calling Transform() with...
string[] inputs = new string[] {
"test12pop90java989python",
"123test12pop90java989python321",
"This text contains no numbers",
"1a2b3c"
};
for (int i = 0; i < inputs.Length; i++)
{
string input = inputs[i];
string output = Transform(input);
Console.WriteLine($" Input[{i}]: \"{input }\"");
Console.WriteLine($"Output[{i}]: \"{output}\"");
Console.WriteLine();
}
...produces this output...
Input[0]: "test12pop90java989python"
Output[0]: "tset12pop90avaj989nohtyp"
Input[1]: "123test12pop90java989python321"
Output[1]: "123tset12pop90avaj989nohtyp321"
Input[2]: "This text contains no numbers"
Output[2]: "srebmun on sniatnoc txet sihT"
Input[3]: "1a2b3c"
Output[3]: "1a2b3c"

A possible solution using Regex and Linq:
using System;
using System.Text.RegularExpressions;
using System.Linq;
public class Program
{
public static void Main()
{
var result = "";
var matchList = Regex.Matches("test12pop90java989python", "([a-zA-Z]*)(\\d*)");
var list = matchList.Cast<Match>().SelectMany(o =>o.Groups.Cast<Capture>().Skip(1).Select(c => c.Value));
foreach (var el in list)
{
if (el.All(char.IsDigit))
{
result += el;
}
else
{
result += new string(el.Reverse().ToArray());
}
}
Console.WriteLine(result);
}
}
I've used code from stackoverflow.com/a/21123574/1037948 to create a list of Regex matches on line 11:
var list = matchList.Cast<Match>().SelectMany(o =>o.Groups.Cast<Capture>().Skip(1).Select(c => c.Value));

Hey you can do something like:
string test = "test12pop90java989python", tempStr = "", finalstr = "";
var charArray = test.ToCharArray();
for (int i = 0; i < charArray.Length; i++)
{
if (!Char.IsNumber(charArray[i]))
{
tempStr += charArray[i];
}
else
{
char[] ReverseString = tempStr.Reverse().ToArray();
foreach (char charItem in ReverseString)
{
finalstr += charItem;
}
tempStr = "";
finalstr += charArray[i];
}
}
if(tempStr != "" && tempStr != null)
{
char[] ReverseString = tempStr.Reverse().ToArray();
foreach (char charItem in ReverseString)
{
finalstr += charItem;
}
tempStr = "";
}
I hope this helps

Related

I am unable to use substring. How can I fix this?

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

Substring word search produces too much output

I am trying to solve the coding problem below:
Given a dictionary of words
And user entered word to compare against
When comparing the given word against the dictionary
Then output all words in the dictionary that exist in the given word
E.g. StartBurst would output Star and Burst if those words were in the dictionary.
Below is my code:
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Enter a word");
string w = Console.ReadLine();
string[] dictionary = new string[106];
{
string word = w;
string word2 = w;
string w1 = word;
string w2 = word2;
for (int n = 0; n < w.Length; n++)
{
w1 = word;
w2 = word;
for (int x = 0; x < word.Length; x++)
{
for (int i = 0; i < dictionary.Length; i++)
{
if (w1.Equals(dictionary[i]) && w1 != w2)
{
Console.WriteLine(w1);
Console.ReadLine();
}
if (w2.Equals(dictionary[i]) && w1 != w2)
{
Console.WriteLine(w2);
Console.ReadLine();
}
}
w1 = w1.Substring(1, w1.Length - 1);
w2 = word.Substring(0, word.Length - x);
}
word = word.Substring(1, word.Length - 1);
}
}
}
}
}
However, when I run this, it outputs far too much output. For example, if I enter "dontdo" the program outputs "dont do do do do do do". I believe this is due to the word = word.Substring(1, word.Length - 1); statement, but I am unsure how to rectify the situation. Can anyone help?
I created a small code snippet for you to find all the substrings that you need in your search.
void Main()
{
foreach(var w in createMatchables("real"))
{
Console.WriteLine(w);
}
}
// this creates all the searchable substrings from a given string
// all the strings are created from left to right
List<string> createMatchables(string str)
{
var matchList = new List<string>();
for (int i = str.Length; i != 0; i--)
{
var branchCount = str.Length / i;
for (int j = 0; j < branchCount; j++)
{
matchList.Add(str.Substring(i*j, i));
}
}
return matchList;
}

Splitting text into lines with maximum length

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();
}

csharp method that choose every second character from the word

I need a method that returns every other character in a string starting with the first character. For example, a method call with ("Java-language") returns "Jv-agae."
private static void NewMethod(string word)
{
// here comes the code
}
var str = "Java-language";
var xx = new string(str.Where((ch, index) => index % 2 == 0).ToArray());
Console.WriteLine(xx);
Or this one:
var xx = string.Join<char>("", str.Where((ch, index) => (index & 1) == 0));
probably little different then everybody else: :-)
protected static IEnumerable<char> EverySecondChar(string word)
{
for(int i = 0; i < word.Length; i += 2)
yield return word[i];
}
string result = new string(EverySecondChar("Java-language").ToArray());
Here is my suggestion for you:
private string TakeEverySecondChar(string input)
{
var result = string.Empty;
for (int i = 0; i < input.Length; i+=2)
{
result += input.Substring(i, 1);
}
return result;
}
Console.Clear();
string Lang = "Java-language";
string[] LangArr = new string[Lang.Length];
char LangChar;
for (int i = 0; i < Lang.Length; i++)
{
LangChar = Lang[i];
LangArr[i] = LangChar.ToString();
}
for (int i = 0; i < LangArr.Length; i++)
{
Console.Write(LangArr[i]);
i++;
}
Console.ReadLine();
public String strip2ndchar(string text)
{
string final="";
int i = 0;
foreach (char a in text.ToCharArray())
{
if (i % 2 == 0)
final += a;
i++;
}
return final;
}

.NET C# Logic Function, recurrent function

I have some string in format like that
XXXX-XXXX-X_X_
All "_" should be replaced with Letters and numberst to prodce sth like that:
XXXX-XXXX-XAXA
XXXX-XXXX-XAXB
XXXX-XXXX-XAXC
XXXX-XXXX-XAXD
XXXX-XXXX-XAXE
XXXX-XXXX-XAXF
XXXX-XXXX-XAXG
(...)
XXXX-XXXX-XZX8
XXXX-XXXX-XZX9
XXXX-XXXX-X0XA
(...)
XXXX-XXXX-X2XA
XXXX-XXXX-X2XB
I know hoe to make it with one "_".
string alphaLetters = "ABCDEFGHIJKLMNOPQRSTUWXYZ0123456789ABCDEF";
foreach (char letter in alphaLetters.ToCharArray())
{
Numbers.Add(number.Replace('_', letter)));
}
I want this code to be working with unknown number of "_".
Can you help?
IMHO it must be recursive. (Note: that does not mean it must use recursive method call, although I used recursive call in the following code, it can be easily converted to internal recursion stack. )
public static void RunSnippet()
{
var r = new List<string>();
Replace("asd_asd_asd_".ToCharArray(), 0, r);
foreach(var s in r) { Console.WriteLine(s); }
}
public static char[] possibilities = new char[] { 'A', 'B', 'C' };
public static void Replace(char[] chars, int startIndex, IList<string> result)
{
for (int i = startIndex; i < chars.Length; i++)
{
if (chars[i] != '_')
{
continue;
}
// we found first '_'
for (int j = 0; j < possibilities.Length; j++)
{
chars[i] = possibilities[j];
Replace(chars, i + 1, result);
}
chars[i] = '_'; // take back what we replaced
return; //we're done here
}
// we didn't find any '_', so all were replaced and we have result:
result.Add(new string(chars));
}
Try this one:
var alphaIndexes = new List<int>();
string alphaLetters = "ABCDEFGHIJKLMNOPQRSTUWXYZ0123456789ABCDEF";
for(int n = 0; n<Numbers.Count; n++) {
char[] numberLetters = Numbers[n].ToCharArray();
int position = 0;
for(int i = numberLetters.Length - 1; i>=0; i--) {
if(numberLetters[i] == '_') {
int alphaIndex = 0;
if(alphaIndexes.Count <= position)
alphaIndexes.Add(0);
else {
alphaIndex = alphaIndexes[position];
}
numberLetters[i] = alphaLetters[alphaIndex];
position++;
}
}
if(alphaIndexes.Count > 0) {
alphaIndexes[0]++;
for(int j = 0; j < alphaIndexes.Count; j++) {
if(alphaIndexes[j] >= alphaLetters.Length) {
alphaIndexes[j] = 0;
if (j < alphaIndexes.Count)
alphaIndexes[j+1]++;
}
}
}
Numbers[n] = new String(numberLetters);
Numbers[n].Dump();
}

Categories