Find 2 letter or 3 letters from wordlist - c#

I have a 256 wordlist with 8 digits like "DDUUDDUU", "DDDDUUUU", "DDUUUUUU" and I am having a hard time trying to match any combination of 2 or 3 consecutive letters like "UUDDUUUU", "DDDUUDDD"
foreach (var eachWord in AAAA.Values) {
int iCountU = 0;
int iCountD = 0;
char iLastChar = (char)106;
foreach (char letter in eachWord) {
if (letter == 'D') {
if (iCountD < 3) {
if (letter != iLastChar) {
iLastChar = letter;
iCountD = 1;
} else {
iCountD += 1;
}
}
}
if (letter == 'U') {
if (iCountU < 3) {
if (letter != iLastChar) {
iLastChar = letter;
iCountU = 1;
} else {
iCountU += 1;
}
}
}
}
if (iCountU > 2 && iCountD > 2) {
BBBB[eachWord] = eachWord;
}
}

Since this implementation counts the maximum consecutive occurrences for each character, the second word evaluates as {2,4} which overrides {2,3} and doesn't count as a match.
int matches = 0;
var wordList = new string[] { "DDUUUDUD", "DDUUUUDU" };
foreach (string word in wordList)
{
char? previous = null;
int count = 0;
var results = new Dictionary<char, int>();
foreach (char letter in word)
{
if (letter == previous)
results[letter] = Math.Max(results.ContainsKey(letter) ? results[letter] : 0, ++count);
else
count = 1;
previous = letter;
}
if (results.Values.SequenceEqual(new int[] {2,3}) || results.Values.SequenceEqual(new int[] {3,2}))
matches++;
}
Console.WriteLine(matches);

I don't have a C# compiler with me, here is a python code (with many element pretending in C# style)
AAAA=["DDUUDDUU", "DDDDUUUU"]
for word in AAAA:
isFirst=True
maxCon=0
currCon=1
for c in word:
if isFirst:
isFirst=False
else:
if c==prev:
currCon+=1
maxCon=max(maxCon,currCon)
else:
currCon=1
prev=c
if maxCon in (2,3):
print(word,maxCon)

This is surprisingly simple with a Regular Expression:
static bool testString(string test)
{
return Regex.Matches(test, #"([a-zA-Z])\1+").Any(x => x.Length == 2 || x.Length == 3);
}
The main trick is that the \1+ will create a group when it encounters a new character and add the next characters that match the first character to that match group.
Note on older .NET versions you may need to use Cast<Match>, as Regex.Matches(test, #"([a-zA-Z])\1+").Cast<Match>().Any(x => x.Length == 2 || x.Length == 3)

Related

How to find number of specific strings in a string in c#

There is a string: xxoxoxoxoxoxooxxxxox where x is a seat that is occupied and o is not, I have to find individual occupied seats, with both sides having an x.
I tried to look at
for (int i = 0; i < string.Length; i++) {
if(string[i]=='x' && string[i + 1]=='o' && string[i + 2] == 'x')
{
count++;
}
}
but i got error so I was wondering if theres a good way to do it.
As the question is pretty unclear, I am assuming that you are looking for a pattern xox and want to know the position of o.
you can run a for loop and get the index.
to get the count of such patterns. you can increment the count by 1.
string str = "xxoxoxoxoxoxooxxxxox";
for(int i = 0; i < str.Length - 2; i++)
{
if (str[i] == 'x' && str[i +1] == 'o' && str[i+ 2] == 'x')
{
Console.WriteLine(i + 1);
count++;
}
}
you can change the character value based on your requirement.
you can use regex.matches to find all matches ...
string s = "xxoxoxoxoxoxooxxxxox";
Regex rx = new Regex("xox");
foreach (Match match in rx.Matches(s))
{
Console.WriteLine("Match index: "+ match.Index);
}
RegEx approach which gives you all indices of individual occupied seats oxo https://dotnetfiddle.net/3jc1Vq
string input = "xxoxoxoxoxoxooxxxxox";
// ^ ^ ^ ^ ^ ^
int[] indices = Regex.Matches(input, "(?<=x)o(?=x)").Cast<Match>().Select(x => x.Index).ToArray();
// in case you only want the count
int count = Regex.Matches(input, "(?<=x)o(?=x)").Count();
I made a working example that makes use of ReadOnlySpan<T> and avoids RegEx and over allocation.
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
string seats = "xxoxoxoxoxoxooxxxxox";
var results = seats.ToCharArray().GetSingles('o');
foreach(var i in results)
{
Console.WriteLine(i);
}
}
}
public static class Ext
{
public static IReadOnlyList<int> GetSingles<T>(this T[] source, T search)
{
var results = new List<int>();
if(source.Length == 0)
{
return results;
}
if (source.Length == 1)
{
if (source[0].Equals(search))
{
results.Add(0);
}
return results;
}
if(source.Length >= 2)
{
if (source[0].Equals(search) && ! source[1].Equals(search))
{
results.Add(0);
}
if (source.Length == 2)
{
if (!source[0].Equals(search) && source[1].Equals(search))
{
results.Add(1);
}
return results;
}
}
ReadOnlySpan<T> window = new ReadOnlySpan<T>(source, 0, 3);
int i = 1;
for(; i < source.Length - 1; i++)
{
window = new ReadOnlySpan<T>(source, i - 1, 3);
if(!window[0].Equals(search) &&
window[1].Equals(search) &&
!window[2].Equals(search))
{
results.Add(i);
}
}
if(!window[1].Equals(search) && window[2].Equals(search))
{
results.Add(i + 1);
}
return results;
}
}
This outputs,
2
4
6
8
10
18
With the more challenging test data,
public class Program
{
public static void Main()
{
var tests = new string[]
{
"",
"o",
"x",
"oo",
"ox",
"xo",
"xx",
"oxx",
"oox",
"xox",
"xoo",
"xoxoxoxo",
"xoxoxoxoo",
"xoxoxox"
};
for(var i = 0; i < tests.Length; i++)
{
string seats = tests[i];
Console.WriteLine($"{i}:\"{seats}\"");
var results = seats.ToCharArray().GetSingles('o');
foreach(var r in results)
{
Console.WriteLine(r);
}
}
}
}
we get the correct output,
0:""
1:"o"
0
2:"x"
3:"oo"
4:"ox"
0
5:"xo"
1
6:"xx"
7:"oxx"
0
8:"oox"
9:"xox"
1
10:"xoo"
11:"xoxoxoxo"
1
3
5
8
12:"xoxoxoxoo"
1
3
5
13:"xoxoxox"
1
3
5

How to create a sequence of strings between "start" and "end" strings [duplicate]

I have a question about iterate through the Alphabet.
I would like to have a loop that begins with "a" and ends with "z". After that, the loop begins "aa" and count to "az". after that begins with "ba" up to "bz" and so on...
Anybody know some solution?
Thanks
EDIT: I forgot that I give a char "a" to the function then the function must return b. if u give "bnc" then the function must return "bnd"
First effort, with just a-z then aa-zz
public static IEnumerable<string> GetExcelColumns()
{
for (char c = 'a'; c <= 'z'; c++)
{
yield return c.ToString();
}
char[] chars = new char[2];
for (char high = 'a'; high <= 'z'; high++)
{
chars[0] = high;
for (char low = 'a'; low <= 'z'; low++)
{
chars[1] = low;
yield return new string(chars);
}
}
}
Note that this will stop at 'zz'. Of course, there's some ugly duplication here in terms of the loops. Fortunately, that's easy to fix - and it can be even more flexible, too:
Second attempt: more flexible alphabet
private const string Alphabet = "abcdefghijklmnopqrstuvwxyz";
public static IEnumerable<string> GetExcelColumns()
{
return GetExcelColumns(Alphabet);
}
public static IEnumerable<string> GetExcelColumns(string alphabet)
{
foreach(char c in alphabet)
{
yield return c.ToString();
}
char[] chars = new char[2];
foreach(char high in alphabet)
{
chars[0] = high;
foreach(char low in alphabet)
{
chars[1] = low;
yield return new string(chars);
}
}
}
Now if you want to generate just a, b, c, d, aa, ab, ac, ad, ba, ... you'd call GetExcelColumns("abcd").
Third attempt (revised further) - infinite sequence
public static IEnumerable<string> GetExcelColumns(string alphabet)
{
int length = 0;
char[] chars = null;
int[] indexes = null;
while (true)
{
int position = length-1;
// Try to increment the least significant
// value.
while (position >= 0)
{
indexes[position]++;
if (indexes[position] == alphabet.Length)
{
for (int i=position; i < length; i++)
{
indexes[i] = 0;
chars[i] = alphabet[0];
}
position--;
}
else
{
chars[position] = alphabet[indexes[position]];
break;
}
}
// If we got all the way to the start of the array,
// we need an extra value
if (position == -1)
{
length++;
chars = new char[length];
indexes = new int[length];
for (int i=0; i < length; i++)
{
chars[i] = alphabet[0];
}
}
yield return new string(chars);
}
}
It's possible that it would be cleaner code using recursion, but it wouldn't be as efficient.
Note that if you want to stop at a certain point, you can just use LINQ:
var query = GetExcelColumns().TakeWhile(x => x != "zzz");
"Restarting" the iterator
To restart the iterator from a given point, you could indeed use SkipWhile as suggested by thesoftwarejedi. That's fairly inefficient, of course. If you're able to keep any state between call, you can just keep the iterator (for either solution):
using (IEnumerator<string> iterator = GetExcelColumns())
{
iterator.MoveNext();
string firstAttempt = iterator.Current;
if (someCondition)
{
iterator.MoveNext();
string secondAttempt = iterator.Current;
// etc
}
}
Alternatively, you may well be able to structure your code to use a foreach anyway, just breaking out on the first value you can actually use.
Edit: Made it do exactly as the OP's latest edit wants
This is the simplest solution, and tested:
static void Main(string[] args)
{
Console.WriteLine(GetNextBase26("a"));
Console.WriteLine(GetNextBase26("bnc"));
}
private static string GetNextBase26(string a)
{
return Base26Sequence().SkipWhile(x => x != a).Skip(1).First();
}
private static IEnumerable<string> Base26Sequence()
{
long i = 0L;
while (true)
yield return Base26Encode(i++);
}
private static char[] base26Chars = "abcdefghijklmnopqrstuvwxyz".ToCharArray();
private static string Base26Encode(Int64 value)
{
string returnValue = null;
do
{
returnValue = base26Chars[value % 26] + returnValue;
value /= 26;
} while (value-- != 0);
return returnValue;
}
The following populates a list with the required strings:
List<string> result = new List<string>();
for (char ch = 'a'; ch <= 'z'; ch++){
result.Add (ch.ToString());
}
for (char i = 'a'; i <= 'z'; i++)
{
for (char j = 'a'; j <= 'z'; j++)
{
result.Add (i.ToString() + j.ToString());
}
}
I know there are plenty of answers here, and one's been accepted, but IMO they all make it harder than it needs to be. I think the following is simpler and cleaner:
static string NextColumn(string column){
char[] c = column.ToCharArray();
for(int i = c.Length - 1; i >= 0; i--){
if(char.ToUpper(c[i]++) < 'Z')
break;
c[i] -= (char)26;
if(i == 0)
return "A" + new string(c);
}
return new string(c);
}
Note that this doesn't do any input validation. If you don't trust your callers, you should add an IsNullOrEmpty check at the beginning, and a c[i] >= 'A' && c[i] <= 'Z' || c[i] >= 'a' && c[i] <= 'z' check at the top of the loop. Or just leave it be and let it be GIGO.
You may also find use for these companion functions:
static string GetColumnName(int index){
StringBuilder txt = new StringBuilder();
txt.Append((char)('A' + index % 26));
//txt.Append((char)('A' + --index % 26));
while((index /= 26) > 0)
txt.Insert(0, (char)('A' + --index % 26));
return txt.ToString();
}
static int GetColumnIndex(string name){
int rtn = 0;
foreach(char c in name)
rtn = rtn * 26 + (char.ToUpper(c) - '#');
return rtn - 1;
//return rtn;
}
These two functions are zero-based. That is, "A" = 0, "Z" = 25, "AA" = 26, etc. To make them one-based (like Excel's COM interface), remove the line above the commented line in each function, and uncomment those lines.
As with the NextColumn function, these functions don't validate their inputs. Both with give you garbage if that's what they get.
Here’s what I came up with.
/// <summary>
/// Return an incremented alphabtical string
/// </summary>
/// <param name="letter">The string to be incremented</param>
/// <returns>the incremented string</returns>
public static string NextLetter(string letter)
{
const string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (!string.IsNullOrEmpty(letter))
{
char lastLetterInString = letter[letter.Length - 1];
// if the last letter in the string is the last letter of the alphabet
if (alphabet.IndexOf(lastLetterInString) == alphabet.Length - 1)
{
//replace the last letter in the string with the first leter of the alphbat and get the next letter for the rest of the string
return NextLetter(letter.Substring(0, letter.Length - 1)) + alphabet[0];
}
else
{
// replace the last letter in the string with the proceeding letter of the alphabet
return letter.Remove(letter.Length-1).Insert(letter.Length-1, (alphabet[alphabet.IndexOf(letter[letter.Length-1])+1]).ToString() );
}
}
//return the first letter of the alphabet
return alphabet[0].ToString();
}
just curious , why not just
private string alphRecursive(int c) {
var alphabet = "abcdefghijklmnopqrstuvwxyz".ToCharArray();
if (c >= alphabet.Length) {
return alphRecursive(c/alphabet.Length) + alphabet[c%alphabet.Length];
} else {
return "" + alphabet[c%alphabet.Length];
}
}
This is like displaying an int, only using base 26 in stead of base 10. Try the following algorithm to find the nth entry of the array
q = n div 26;
r = n mod 26;
s = '';
while (q > 0 || r > 0) {
s = alphabet[r] + s;
q = q div 26;
r = q mod 26;
}
Of course, if you want the first n entries, this is not the most efficient solution. In this case, try something like daniel's solution.
I gave this a go and came up with this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Alphabetty
{
class Program
{
const string alphabet = "abcdefghijklmnopqrstuvwxyz";
static int cursor = 0;
static int prefixCursor;
static string prefix = string.Empty;
static bool done = false;
static void Main(string[] args)
{
string s = string.Empty;
while (s != "Done")
{
s = GetNextString();
Console.WriteLine(s);
}
Console.ReadKey();
}
static string GetNextString()
{
if (done) return "Done";
char? nextLetter = GetNextLetter(ref cursor);
if (nextLetter == null)
{
char? nextPrefixLetter = GetNextLetter(ref prefixCursor);
if(nextPrefixLetter == null)
{
done = true;
return "Done";
}
prefix = nextPrefixLetter.Value.ToString();
nextLetter = GetNextLetter(ref cursor);
}
return prefix + nextLetter;
}
static char? GetNextLetter(ref int letterCursor)
{
if (letterCursor == alphabet.Length)
{
letterCursor = 0;
return null;
}
char c = alphabet[letterCursor];
letterCursor++;
return c;
}
}
}
Here is something I had cooked up that may be similar. I was experimenting with iteration counts in order to design a numbering schema that was as small as possible, yet gave me enough uniqueness.
I knew that each time a added an Alpha character, it would increase the possibilities 26x but I wasn't sure how many letters, numbers, or the pattern I wanted to use.
That lead me to the code below. Basically you pass it an AlphaNumber string, and every position that has a Letter, would eventually increment to "z\Z" and every position that had a Number, would eventually increment to "9".
So you can call it 1 of two ways..
//This would give you the next Itteration... (H3reIsaStup4dExamplf)
string myNextValue = IncrementAlphaNumericValue("H3reIsaStup4dExample")
//Or Loop it resulting eventually as "Z9zzZzzZzzz9zZzzzzzz"
string myNextValue = "H3reIsaStup4dExample"
while (myNextValue != null)
{
myNextValue = IncrementAlphaNumericValue(myNextValue)
//And of course do something with this like write it out
}
(For me, I was doing something like "1AA000")
public string IncrementAlphaNumericValue(string Value)
{
//We only allow Characters a-b, A-Z, 0-9
if (System.Text.RegularExpressions.Regex.IsMatch(Value, "^[a-zA-Z0-9]+$") == false)
{
throw new Exception("Invalid Character: Must be a-Z or 0-9");
}
//We work with each Character so it's best to convert the string to a char array for incrementing
char[] myCharacterArray = Value.ToCharArray();
//So what we do here is step backwards through the Characters and increment the first one we can.
for (Int32 myCharIndex = myCharacterArray.Length - 1; myCharIndex >= 0; myCharIndex--)
{
//Converts the Character to it's ASCII value
Int32 myCharValue = Convert.ToInt32(myCharacterArray[myCharIndex]);
//We only Increment this Character Position, if it is not already at it's Max value (Z = 90, z = 122, 57 = 9)
if (myCharValue != 57 && myCharValue != 90 && myCharValue != 122)
{
myCharacterArray[myCharIndex]++;
//Now that we have Incremented the Character, we "reset" all the values to the right of it
for (Int32 myResetIndex = myCharIndex + 1; myResetIndex < myCharacterArray.Length; myResetIndex++)
{
myCharValue = Convert.ToInt32(myCharacterArray[myResetIndex]);
if (myCharValue >= 65 && myCharValue <= 90)
{
myCharacterArray[myResetIndex] = 'A';
}
else if (myCharValue >= 97 && myCharValue <= 122)
{
myCharacterArray[myResetIndex] = 'a';
}
else if (myCharValue >= 48 && myCharValue <= 57)
{
myCharacterArray[myResetIndex] = '0';
}
}
//Now we just return an new Value
return new string(myCharacterArray);
}
}
//If we got through the Character Loop and were not able to increment anything, we retun a NULL.
return null;
}
Here's my attempt using recursion:
public static void PrintAlphabet(string alphabet, string prefix)
{
for (int i = 0; i < alphabet.Length; i++) {
Console.WriteLine(prefix + alphabet[i].ToString());
}
if (prefix.Length < alphabet.Length - 1) {
for (int i = 0; i < alphabet.Length; i++) {
PrintAlphabet(alphabet, prefix + alphabet[i]);
}
}
}
Then simply call PrintAlphabet("abcd", "");

Remove and Add letters in Strings

I am trying to solve a problem in C#.
Here is the task:
If a word begins with a vowel (a, e, i, o, u or A, E, I, O, U), remove
the first letter and append it to the end, then add "che". If you have
the word “orange” It translates to “rangeoche”
If a word begins with a consonant (i.e. not a vowel), append "che" to the end of the word. For example, the word "chicken" becomes
"chickenche".
If the word has even number of letters append one more "e" to the end of it.
Print the translated sentence.
Example:
Hello there Amy
Output:
Helloche thereche myAche
Here is what I have done so far :
string Sentence = Console.ReadLine();
string[] output = Sentence.Split(' ');
char letter;
string che = "che";
StringBuilder sb = new StringBuilder(Sentence);
foreach (string s in output)
{
letter = s[0];
if (letter == 'a' || letter == 'A' || letter == 'e' || letter == 'E' || letter == 'i'
|| letter == 'I' || letter == 'o' || letter == 'O' || letter == 'u' || letter == 'U')
{
// Console.WriteLine("first char of the word is a vowel");
}
else
{
sb.Insert(s.Length,che);
// Console.WriteLine("first char of a word is a consonant");
}
if (s.Length % 2 == 0)
{
// Console.WriteLine("the word has even numbers of letters");
}
//Console.WriteLine(firstchar);
int currentWordLength = s.Length;
}
Console.WriteLine(sb);
The problem is I cannot add "che" or remove vowels of words because the index is moving due to those changes. I can only change the first word. My ifs are correct because if I uncomment the Console.Writelines they scan through each word.
I am just struggling with the adding/removing of each word. Can you please point me to the right direction?
I would suggest you to create StringBuilder object and append appropriate string into the IF condition. Try with the below code:
string Sentence = Console.ReadLine();
string[] output = Sentence.Split(' ');
char letter;
string che = "che";
StringBuilder sb = null;
Console.WriteLine("\n");
string strFinal = "";
foreach (string s in output)
{
letter = s[0];
sb = new StringBuilder(s);
if (letter == 'a' || letter == 'A' || letter == 'e' || letter == 'E' || letter == 'i'
|| letter == 'I' || letter == 'o' || letter == 'O' || letter == 'u' || letter == 'U')
{
// Console.WriteLine("first char of the word is a vowel");
string s1 = sb.Remove(0, 1).ToString();
sb.Insert(s1.Length, letter);
sb.Insert(sb.Length, che);
}
else
{
// Console.WriteLine("first char of a word is a consonant");
sb.Insert(s.Length, che);
}
if (s.Length % 2 == 0)
{
// Console.WriteLine("the word has even numbers of letters");
// sb.Insert(s.Length, "e");
sb.Insert(sb.Length, "e");
}
//Console.WriteLine(firstchar);
int currentWordLength = s.Length;
strFinal += sb + " ";
}
Console.WriteLine(strFinal);
Console.ReadKey();
First, I'd recommend changing your translation code to have a function that acts on words, instead of the whole sentence. So the code in foreach (string s in output) should be moved to another function that just acts on that string. And don't try to manipulate the string passed it, create a new one based on the logic you've listed. Once you've created the translated string, return it to the caller. The caller would then reconstruct the sentence from each returned translation.
Using the obvious extension methods:
public static class ExtensionMethods {
// ***
// *** int Extensions
// ***
public static bool IsEven(this int n) => n % 2 == 0;
// ***
// *** String Extensions
// ***
public static bool StartsWithOneOf(this string s, HashSet<char> starts) => starts.Contains(s[0]);
public static string Join(this IEnumerable<string> strings, string sep) => String.Join(sep, strings);
}
You can use LINQ to process the rules:
var vowels = "aeiouAEIOU".ToHashSet();
var ans = src.Split(' ')
.Select(w => (w.StartsWithOneOf(vowels) ? w.Substring(1)+w[0] : w)+"che"+(w.Length.IsEven() ? "e" : ""))
.Join(" ");
Let's start from splitting the initial problem into smaller ones, with a help of extract methods:
using using System.Text.RegularExpressions;
...
private static String ConvertWord(string word) {
//TODO: Solution here
return word; // <- Stub
}
private static String ConvertPhrase(string phrase) {
// Regex (not Split) to preserve punctuation:
// we convert each word (continued sequence of letter A..Z a..z or ')
// within the original phrase
return Regex.Replace(phrase, #"[A-Za-z']+", match => ConvertWord(match.Value));
// Or if there's guarantee, that space is the only separator:
// return string.Join(" ", phrase
// .Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)
// .Select(item => ConvertWord(item)));
}
Now it's time to implement ConvertWord:
private static String ConvertWord(string word) {
// Do not forget of special cases - e.g. empty string
if (string.IsNullOrEmpty(word))
return "chee";
// If the word has even number of letters append one more "e" to the end of it.
string suffix = word.Length % 2 == 0 ? "chee" : "che";
// To cases: starting from vowel / consonant
char letter = char.ToUpper(word[0]);
if (letter == 'A' || letter == 'E' || letter == 'I' || letter == 'O' || letter == 'U')
return word.Substring(1) + word.Substring(0, 1) + suffix;
else
return word + suffix;
}
Finally
string Sentence = Console.ReadLine();
Console.Write(ConvertPhrase(Sentence));
For test input
"It's just a simple test (demo only): nothing more!"
Will get
t'sIchee justchee ache simplechee testchee (demochee nlyochee): nothingche morechee!
You mustn't change your word before the end of ifs. you need to test all of the conditions and save the result in another values, finally do changes on the word:
foreach (string s in output)
{
letter = char.ToLower(s[0]);
bool isVowel = false;
bool isEven = false;
if (letter == 'a' || letter == 'e' || letter == 'i'
|| letter == 'o' || letter == 'u')
{
isVowel = true;
}
if (s.Length % 2 == 0)
{
isEven = true;
}
//Now you can change the word
if (isVowel)
{
//Do What you want
}
if (isEven)
{
//Do What you want
}
//Console.WriteLine(firstchar);
int currentWordLength = s.Length;
}
I would say break the logic into specific units so you can write tests,
static void Main(string[] args)
{
var input = Console.ReadLine();
var inputs = input.Split(' ');
var sentence = string.Join(" ", inputs.Select(ConvertWord));
Console.Write(sentence);
Console.Read();
}
internal static string ConvertWord(string input)
{
const string che = "che";
var vowels = new List<string>
{
"a","A", "e", "E", "i", "I", "o", "O", "u", "U"
};
var firstChar = input.First();
var startsWithVowel = vowels.SingleOrDefault(a => a.Equals(firstChar));
string rule2String, output;
if (string.IsNullOrEmpty(startsWithVowel))
{
output = input + che;
}
else
{
output = input.Substring(1) + startsWithVowel + che;
}
rule2String = IsLengthEven(input)
? output + "e"
: output
;
return rule2String;
}
internal static bool IsLengthEven(string input)
{
return input.Length % 2 == 0;
}
Hope this Helps!
PS: I have not covered the edge cases
I would recommend to use String.Join using Linq with String.Format. Then the solution is quite easy:
private String convertSentence() {
var sentence = "Hello there Amy";
var vowels = "aeiou";
var che = "che";
return String.Join(" ", (
from s in sentence.Split(' ')
let moveFirstToEnd = vowels.Contains(s.ToLower()[0]) && s.Length > 1
select String.Format("{0}{1}{2}{3}"
, moveFirstToEnd ? s.Substring(1) : s
, moveFirstToEnd ? s.Substring(0, 1) : String.Empty
, che
, s.Length % 2 == 0 ? "e" : String.Empty
)
)
);
}

C# How to convert a list of strings with not a single character to char?

I have list of strings which has such items inside - 65,66... so on.
When I'm trying to use Convert.ToChar(item), I'm getting error that single string should have only one character. What I can't understood is what I can really use besides the Convert function to turn 65 (string) into char = A value.
static void Main(string[] args)
{
List<char> Alphabet = new List<char>();
List<string> Message = new List<string>();
for (int i = 65; i < 91; i++)
{
Alphabet.Add((char)i);
}
var stroke = Console.ReadLine().ToString();
foreach (var letter in stroke)
{
if (Alphabet[Alphabet.Count - 1] == letter)
{
Message.Add((66.ToString()));
}
if (Alphabet[Alphabet.Count - 2] == letter)
{
Message.Add((65.ToString()));
}
if (Convert.ToChar(" ") == letter)
{
Message.Add(" ");
}
foreach (var item in Alphabet)
{
if (item == letter && letter != Alphabet[Alphabet.Count -1] && letter != Alphabet[Alphabet.Count - 2])
{
Message.Add((item + 2).ToString());
}
}
}
foreach (var item in Message)
{
if (item != " ")
{
Console.Write(Convert.ToChar(Convert.ToInt16(item)));
}
else
{
Console.Write(" ");
}
}
Console.ReadLine();}
Here is ending working code, for those who may wonder why i need such type of convert.Its Caesarus encrypter. Working only for upper-case letters but its working now with all help of those guys above.
If items of your list are int values such as 65,66, ... that seems to be character codes, you can try:
Convert.ToChar(Convert.ToInt32(item))
For example:
var str="65";
var chr= Convert.ToChar(Convert.ToInt32(str));
//The output is A
Encryption:
var stroke = Console.ReadLine();
var enc = new String(stroke.ToCharArray().Select(c=>Convert.ToChar(c+2)).ToArray());
Console.WriteLine(enc);

How to split text into words?

How to split text into words?
Example text:
'Oh, you can't help that,' said the Cat: 'we're all mad here. I'm mad. You're mad.'
The words in that line are:
Oh
you
can't
help
that
said
the
Cat
we're
all
mad
here
I'm
mad
You're
mad
Split text on whitespace, then trim punctuation.
var text = "'Oh, you can't help that,' said the Cat: 'we're all mad here. I'm mad. You're mad.'";
var punctuation = text.Where(Char.IsPunctuation).Distinct().ToArray();
var words = text.Split().Select(x => x.Trim(punctuation));
Agrees exactly with example.
First, Remove all special characeters:
var fixedInput = Regex.Replace(input, "[^a-zA-Z0-9% ._]", string.Empty);
// This regex doesn't support apostrophe so the extension method is better
Then split it:
var split = fixedInput.Split(' ');
For a simpler C# solution for removing special characters (that you can easily change), add this extension method (I added a support for an apostrophe):
public static string RemoveSpecialCharacters(this string str) {
var sb = new StringBuilder();
foreach (char c in str) {
if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '\'' || c == ' ') {
sb.Append(c);
}
}
return sb.ToString();
}
Then use it like so:
var words = input.RemoveSpecialCharacters().Split(' ');
You'll be surprised to know that this extension method is very efficient (surely much more efficient then the Regex) so I'll suggest you use it ;)
Update
I agree that this is an English only approach but to make it Unicode compatible all you have to do is replace:
(c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')
With:
char.IsLetter(c)
Which supports Unicode, .Net Also offers you char.IsSymbol and char.IsLetterOrDigit for the variety of cases
Just to add a variation on #Adam Fridental's answer which is very good, you could try this Regex:
var text = "'Oh, you can't help that,' said the Cat: 'we're all mad here. I'm mad. You're mad.'";
var matches = Regex.Matches(text, #"\w+[^\s]*\w+|\w");
foreach (Match match in matches) {
var word = match.Value;
}
I believe this is the shortest RegEx that will get all the words
\w+[^\s]*\w+|\w
If you don't want to use a Regex object, you could do something like...
string mystring="Oh, you can't help that,' said the Cat: 'we're all mad here. I'm mad. You're mad.";
List<string> words=mystring.Replace(",","").Replace(":","").Replace(".","").Split(" ").ToList();
You'll still have to handle the trailing apostrophe at the end of "that,'"
This is one of solution, i dont use any helper class or method.
public static List<string> ExtractChars(string inputString) {
var result = new List<string>();
int startIndex = -1;
for (int i = 0; i < inputString.Length; i++) {
var character = inputString[i];
if ((character >= 'a' && character <= 'z') ||
(character >= 'A' && character <= 'Z')) {
if (startIndex == -1) {
startIndex = i;
}
if (i == inputString.Length - 1) {
result.Add(GetString(inputString, startIndex, i));
}
continue;
}
if (startIndex != -1) {
result.Add(GetString(inputString, startIndex, i - 1));
startIndex = -1;
}
}
return result;
}
public static string GetString(string inputString, int startIndex, int endIndex) {
string result = "";
for (int i = startIndex; i <= endIndex; i++) {
result += inputString[i];
}
return result;
}
If you want to use the "for cycle" to check each char and save all punctuation in the input string I've create this class. The method GetSplitSentence() return a list of SentenceSplitResult. In this list there are saved all the words and all the punctuation & numbers. Each punctuation or numbers saved is an item in the list. The sentenceSplitResult.isAWord is used to check if is a word or not. [Sorry for my English]
public class SentenceSplitResult
{
public string word;
public bool isAWord;
}
public class StringsHelper
{
private readonly List<SentenceSplitResult> outputList = new List<SentenceSplitResult>();
private readonly string input;
public StringsHelper(string input)
{
this.input = input;
}
public List<SentenceSplitResult> GetSplitSentence()
{
StringBuilder sb = new StringBuilder();
try
{
if (String.IsNullOrEmpty(input)) {
Logger.Log(new ArgumentNullException(), "GetSplitSentence - input is null or empy");
return outputList;
}
bool isAletter = IsAValidLetter(input[0]);
// Each char i checked if is a part of a word.
// If is YES > I can store the char for later
// IF is NO > I Save the word (if exist) and then save the punctuation
foreach (var _char in input)
{
isAletter = IsAValidLetter(_char);
if (isAletter == true)
{
sb.Append(_char);
}
else
{
SaveWord(sb.ToString());
sb.Clear();
SaveANotWord(_char);
}
}
SaveWord(sb.ToString());
}
catch (Exception ex)
{
Logger.Log(ex);
}
return outputList;
}
private static bool IsAValidLetter(char _char)
{
if ((Char.IsPunctuation(_char) == true) || (_char == ' ') || (Char.IsNumber(_char) == true))
{
return false;
}
return true;
}
private void SaveWord(string word)
{
if (String.IsNullOrEmpty(word) == false)
{
outputList.Add(new SentenceSplitResult()
{
isAWord = true,
word = word
});
}
}
private void SaveANotWord(char _char)
{
outputList.Add(new SentenceSplitResult()
{
isAWord = false,
word = _char.ToString()
});
}
You could try using a regex to remove the apostrophes that aren't surrounded by letters (i.e. single quotes) and then using the Char static methods to strip all the other characters. By calling the regex first you can keep the contraction apostrophes (e.g. can't) but remove the single quotes like in 'Oh.
string myText = "'Oh, you can't help that,' said the Cat: 'we're all mad here. I'm mad. You're mad.'";
Regex reg = new Regex("\b[\"']\b");
myText = reg.Replace(myText, "");
string[] listOfWords = RemoveCharacters(myText);
public string[] RemoveCharacters(string input)
{
StringBuilder sb = new StringBuilder();
foreach (char c in input)
{
if (Char.IsLetter(c) || Char.IsWhiteSpace(c) || c == '\'')
sb.Append(c);
}
return sb.ToString().Split(' ');
}

Categories