Is there a simple way to apply grammatical casing to a string? - c#

I am developing a Xamarin.Forms application on UWP
I have an Editor control - Basically a multi-line TextBox
I am trying to apply some simple grammatical casing to the string basically the following:
Capitalise the word "I"
Capitalise the First word
Capitalise the First word after a full stop.
I have managed to do the first two, and am a bit stuck on the third and was wondering if there is an easier way or whether my algorithm can be adapted.
What I have so far is:
public static string ToGramaticalCase(this string s)
{
var thingsToCapitalise = new String[] {"i"};
string newString = string.Empty;
if (!string.IsNullOrEmpty(s))
{
var wordSplit = s.Split(' ');
if (wordSplit.Count() > 1)
{
var wordToCapitalise = wordSplit.First();
wordToCapitalise = wordToCapitalise.Substring(0, 1).ToUpper() + wordToCapitalise.Substring(1);
var value = wordToCapitalise + s.Substring(wordToCapitalise.Length);
foreach (var item in thingsToCapitalise)
{
value = value.Replace(string.Format(" {0} ", item), string.Format(" {0} ", item.ToUpper()));
}
newString = value;
}
}
return newString;
}

This method will capitalize all words after ". ":
[Test]
public void Test()
{
var result = NewSentenceWithUpperLetter("Sentence one. sentence two.");
// result will be 'Sentence one. Sentence two.'
}
private string NewSentenceWithUpperLetter(string text)
{
var splitted = text.Split(' ');
for (var i = 1; i < splitted.Length; i++)
{
if (splitted[i - 1].EndsWith("."))
{
splitted[i] = splitted[i][0].ToString().ToUpper() + splitted[i].Substring(1);
}
}
return string.Join(" ", splitted);
}

Just split the string also on full stop. Change this line:
var wordSplit = s.Split(' ');
Into this:
var wordSplit = s.Split(new char[] { ' ', '.' },StringSplitOptions.RemoveEmptyEntries);
Edit
This extension method would do what you want:
public static string ToTitleCase(this string input)
{
string output =
String.Join(" ", input.Split(new char[] { ' ' },StringSplitOptions.RemoveEmptyEntries)
.ToList()
.Select(x => x = x.Length>1?
x.First().ToString().ToUpper() + x.Substring(1):
x.First().ToString().ToUpper()));
output =
String.Join(".", output.Split(new char[] { '.' },StringSplitOptions.RemoveEmptyEntries)
.ToList()
.Select(x => x = x.Length > 1 ?
x.First().ToString().ToUpper() + x.Substring(1) :
x.First().ToString().ToUpper()));
return output;
}
Test string: string input = "i try this test sentence .now it works as i want";
Output: I Try This Test Sentence .Now It Works As I Want

Related

problems with for loop string

I'm new to programming in c# and I'm trying to figure out how I could
potentially reverse all words except words containing e in a string.
my current code will detect words containing e, and just writes them down in another textbox:
string text = txbInput.Text;
var words = text.Split(' ');
for (int i = 0; i < words.Length; i++)
{
if (words[i].Contains('e'))
{
txbOutput.Text += words[i];
}
Current:
Input: chicken crossing the road
Output: chickenthe
.
Expected outcome:
Input: chicken crossing the road
Output chicken gnissorc the daor
You can simply split the word on the space character, then, for each word, select either the word itself, or the word reversed (depending on whether or not it contains the 'e' character), and then join them back together again with the space character:
txbOutput.Text = string.Join(" ", txbInput.Text.Split(' ')
.Select(word => word.Contains("e") ? string.Concat(word.Reverse()) : word));
Outputs: chicken gnissorc the daor
using System;
namespace ConsoleApp4
{
class Program
{
static void Main(string[] args)
{
var input = "chicken crossing the road";
foreach (var item in input.Split(' '))
{
if (item.Contains('e'))
{
Console.Write(item + ' ');
}
else
{
Console.Write(Reverse(item) + ' ');
}
}
}
public static string Reverse(string s)
{
char[] charArray = s.ToCharArray();
Array.Reverse(charArray);
return new string(charArray);
}
}
}
enter code here
EDIT
foreach (var item in input.Split(' '))
{
if (item.Contains('e'))
{
txbOutput.Text = txbOutput.Text+ item + ' ';
}
else
{
txbOutput.Text= txbOutput.Text+ Reverse(item) + ' ';
}
}
You can try using the following code -
string.Join(” “,
str.Split(‘ ‘)
.Select(x => new String(x.Reverse().ToArray()))
.ToArray());
Copied from - https://www.declarecode.com/code-solutions/csharp/caprogramtoreverseeachwordinthegivenstring

English to PigLatin Conversion of a Sentence

I am making a program to convert English to PigLatin. However, my solution only seems to work with one word. If I enter in more than ond word, only the last is translated.
testing one translation
Would simply output:
translationway
I've looked at some solutions, but most are in the same fashion as mine, or use "simplified" solutions beyond the scope of my knowledge.
Code:
static void Main(string[] args)
{
Console.WriteLine("Enter a sentence to convert to PigLatin:");
string sentence = Console.ReadLine();
string pigLatin = ToPigLatin(sentence);
Console.WriteLine(pigLatin);
}
static string ToPigLatin (string sentence)
{
string firstLetter,
restOfWord,
vowels = "AEIOUaeio";
int currentLetter;
foreach (string word in sentence.Split())
{
firstLetter = sentence.Substring(0, 1);
restOfWord = sentence.Substring(1, sentence.Length - 1);
currentLetter = vowels.IndexOf(firstLetter);
if (currentLetter == -1)
{
sentence = restOfWord + firstLetter + "ay";
}
else
{
sentence = word + "way";
}
}
return sentence;
All help is greatly appreciated!
Edit
Thanks to great feedback, I've updated my code:
static string ToPigLatin (string sentence)
{
const string vowels = "AEIOUaeio";
List<string> pigWords = new List<string>();
foreach (string word in sentence.Split(' '))
{
string firstLetter = word.Substring(0, 1);
string restOfWord = word.Substring(1, word.Length - 1);
int currentLetter = vowels.IndexOf(firstLetter);
if (currentLetter == -1)
{
pigWords.Add(restOfWord + firstLetter + "ay");
}
else
{
pigWords.Add(word + "way");
}
}
return string.Join(" ", pigWords);
}
Would it be very complex to adapt this code to work with consonant clusters?
For example, right now testing one translation prints as:
estingtay oneway ranslationtay
While, as I understand PigLatin rules, it should read:
estingtay oneway anslationtray
Just place += instead of = here:
if (currentLetter == -1)
{
sentence += restOfWord + firstLetter + "ay";
}
else
{
sentence += word + "way";
}
On your version, you were overriding the sentence in each iteration of your loop
Edit
I've made a lot of changes to the code:
public static string ToPigLatin(string sentence)
{
const string vowels = "AEIOUaeio";
List<string> newWords = new List<string>();
foreach (string word in sentence.Split(' '))
{
string firstLetter = word.Substring(0, 1);
string restOfWord = word.Substring(1, word.Length - 1);
int currentLetter = vowels.IndexOf(firstLetter);
if (currentLetter == -1)
{
newWords.Add(restOfWord + firstLetter + "ay");
}
else
{
newWords.Add(word + "way");
}
}
return string.Join(" ", newWords);
}
As Panagiotis-Kanavos said, and he's damn right, don't build your output on your input but with your input. Thus, I added the newWords list (some might prefer a StringBuilder, I don't).
You were misusing your variable in your loop, especially with the Substrings calls, it's now fixed.
If you have any question on this, don't hesitate.
private static void Main(string[] args)
{
Console.WriteLine("Enter a sentence to convert to PigLatin:");
string sentence = Console.ReadLine();
var pigLatin = GetSentenceInPigLatin(sentence);
Console.WriteLine(pigLatin);
Console.ReadLine();
}
private static string GetSentenceInPigLatin(string sentence)
{
const string vowels = "AEIOUaeio";
var returnSentence = "";
foreach (var word in sentence.Split())
{
var firstLetter = word.Substring(0, 1);
var restOfWord = word.Substring(1, word.Length - 1);
var currentLetter = vowels.IndexOf(firstLetter, StringComparison.Ordinal);
if (currentLetter == -1)
{
returnSentence += restOfWord + firstLetter + "ay ";
}
else
{
returnSentence += word + "way ";
}
}
return returnSentence;
}
I came up with a short LINQ implementation for this:
string.Join(" ", "testing one translation".Split(' ')
.Select(word => "aeiouy".Contains(word[0])
? word.Skip(1).Concat(word.Take(1))
: word.ToCharArray())
.Select(word => word.Concat("way".ToCharArray()))
.Select(word => string.Concat(word)));
Output: "testingway neoway translationway"
Of course, I'd probably refactor it to something like this:
"testing one translation"
.Split(' ')
.Select(word => word.ToCharsWithStartingVowelLast())
.Select(word => word.WithEnding("way"))
.Select(word => string.Concat(word))
.Join(' ');
static class Extensions {
public static IEnumerable<char> ToCharsWithStartingVowelLast(this string word)
{
return "aeiouy".Contains(word[0])
? word.Skip(1).Concat(word.Take(1))
: word.ToCharArray();
}
public static IEnumerable<char> WithEnding(this IEnumerable<char> word, string ending)
{
return word.Concat(ending.ToCharArray())
}
public static string Join(this IEnumerable<IEnumerable<char>> words, char separator)
{
return string.Join(separator, words.Select(word => string.Concat(word)));
}
}
Update:
With your edit, you asked about consonant clusters. One of the things I like about doing this with LINQ is that it's pretty simple to just update that part of the pipeline, and make it all work:
public static IEnumerable<char> ToCharsWithStartingConsonantsLast(this string word)
{
return word.SkipWhile(c => c.IsConsonant()).Concat(word.TakeWhile(c => c.IsConsonant()));
}
public static bool IsConsonant(this char c)
{
return !"aeiouy".Contains(c);
}
The entire pipeline, without refactoring to extension methods, now looks like this:
string.Join(" ", "testing one translation".Split(' ')
.Select(word => word.SkipWhile(c => !"aeiouy".Contains(c)).Concat(word.TakeWhile(c => !"aeiou".Contains(c))))
.Select(word => word.Concat("way".ToCharArray()))
.Select(word => string.Concat(word)))
and outputs "estingtway oneway anslationtrway".
Update 2:
I noticed I wasn't handling word endings correctly. Here's an update that takes care of only adding w to the ending when the word (without the ending) ends with a vowel:
string.Join(" ", "testing one translation".Split(' ')
.Select(word => word.SkipWhile(c => !"aeiouy".Contains(c)).Concat(word.TakeWhile(c => !"aeiou".Contains(c))))
.Select(word =>
{
var ending = "aeiouy".Contains(word.Last()) ? "way" : "ay";
return word.Concat(ending.ToCharArray());
})
.Select(word => string.Concat(word)))
Output: "estingtay oneway anslationtray". Note how it's only the step that handles adding the ending that changed - all other parts of the algorithm were unchanged.
Given how simple this now is, I'd probably only use two extension methods: Join(this IEnumerable<IEnumerable<char>> words, char separator) and IsConsonant(this char c) (the implementation of the latter should be easy given the code samples above). This yields the following final implementation:
"testing one translation"
.Split(' ')
.Select(word => word.SkipWhile(c => !c.IsVowel()).Concat(word.TakeWhile(c => c.IsVowel())))
.Select(word => word.Concat((word.Last().IsVowel() ? "way" : "ay").ToCharArray()))
.Select(word => string.Concat(word))
.Join(" ")
It's also really easy to see here what we do to translate:
Split the sentence into words
Shuffle any consonants to the end of the word (it's admittedly not apparent at first sight that this is what happens, but I can't find a simpler way to express it except by wrapping it in an extension method)
Add the ending
Convert IEnumerable<char>s to strings
Re-join the words into a sentence

Parsing a string with, seemingly, no delimiter

I have the following string that I need to parse out so I can insert them into a DB. The delimiter is "`":
`020 Some Description `060 A Different Description `100 And Yet Another `
I split the string into an array using this
var responseArray = response.Split('`');
So then each item in the responseArrray[] looks like this: 020 Some Description
How would I get the two different parts out of that array? The 1st part will be either 3 or 4 characters long. 2nd part will be no more then 35 characters long.
Due to some ridiculous strangeness beyond my control there is random amounts of space between the 1st and 2nd part.
Or put the other two answers together, and get something that's more complete:
string[] response = input.Split(`);
foreach (String str in response) {
int splitIndex = str.IndexOf(' ');
string num = str.Substring(0, splitIndex);
string desc = str.Substring(splitIndex);
desc.Trim();
}
so, basically you use the first space as a delimiter to create 2 strings. Then you trim the second one, since trim only applies to leading and trailing spaces, not everything in between.
Edit: this a straight implementation of Brad M's comment.
You can try this solution:
var inputString = "`020 Some Description `060 A Different Description `100 And Yet Another `";
int firstWordLength = 3;
int secondWordMaxLength = 35;
var result =inputString.Split('`')
.SelectMany(x => new[]
{
new String(x.Take(firstWordLength).ToArray()).Trim(),
new String(x.Skip(firstWordLength).Take(secondWordMaxLength).ToArray()).Trim()
});
Here is the result in LINQPad:
Update: My first solution has some problems because the use of Trim after Take.Here is another approach with an extension method:
public static class Extensions
{
public static IEnumerable<string> GetWords(this string source,int firstWordLengt,int secondWordLenght)
{
List<string> words = new List<string>();
foreach (var word in source.Split(new[] {'`'}, StringSplitOptions.RemoveEmptyEntries))
{
var parts = word.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries);
words.Add(new string(parts[0].Take(firstWordLengt).ToArray()));
words.Add(new string(string.Join(" ",parts.Skip(1)).Take(secondWordLenght).ToArray()));
}
return words;
}
}
And here is the test result:
Try this
string response = "020 Some Description060 A Different Description 100 And Yet Another";
var responseArray = response.Split('`');
string[] splitArray = {};
string result = "";
foreach (string it in responseArray)
{
splitArray = it.Split(' ');
foreach (string ot in splitArray)
{
if (!string.IsNullOrWhiteSpace(ot))
result += "-" + ot.Trim();
}
}
splitArray = result.Substring(1).Split('-');
string[] entries = input.Split('`');
foreach (string s in entries)
GetStringParts(s);
IEnumerable<String> GetStringParts(String input)
{
foreach (string s in input.Split(' ')
yield return s.Trim();
}
Trim only removes leading/trailing whitespace per MSDN, so spaces in the description won't hurt you.
If the first part is an integer
And you need to account for some empty
For me the first pass was empty
public void parse()
{
string s = #"`020 Some Description `060 A Different Description `100 And Yet Another `";
Int32 first;
String second;
if (s.Contains('`'))
{
foreach (string firstSecond in s.Split('`'))
{
System.Diagnostics.Debug.WriteLine(firstSecond);
if (!string.IsNullOrEmpty(firstSecond))
{
firstSecond.TrimStart();
Int32 firstSpace = firstSecond.IndexOf(' ');
if (firstSpace > 0)
{
System.Diagnostics.Debug.WriteLine("'" + firstSecond.Substring(0, firstSpace) + "'");
if (Int32.TryParse(firstSecond.Substring(0, firstSpace), out first))
{
System.Diagnostics.Debug.WriteLine("'" + firstSecond.Substring(firstSpace-1) + "'");
second = firstSecond.Substring(firstSpace).Trim();
}
}
}
}
}
}
You can get the first part by finding the first space and make a substring. The second is also a Substring. Try something like this.
foreach(string st in response)
{
int index = response.IndexOf(' ');
string firstPart = response.Substring(0, index);
//string secondPart = response.Substring(response.Lenght-35);
//better use this
string secondPart = response.Substring(index);
secondPart.Trim();
}

Split string with colon (:) and separate the numbers with colon

Hello i had a problem on separating a string.
Below are the sample string.
Input - D93:E93 E98 E9:E10 E26 D76:E76 D83:E83 D121:D124
Output - D93, E93, E98, E9, E10, E26, D76, E76, D83, E83, D121, D122, D123, D124
If you separate the two with the same letter it continues counting.
Please help me..
Regards,
You can do:
var input = "D93:E93 E98 E9:E10 E26 D76:E76 D83:E83 D121:D124";
var list = input.Split(' ');
var result = new List<String>();
foreach (var item in list)
{
var parts = item.Split(':');
if (parts.Length == 1) result.Add(parts[0]);
else
{
if (parts[0].Substring(0, 1).CompareTo(parts[1].Substring(0, 1)) == 0)
{
var i = Convert.ToInt32(parts[0].Substring(1));
var j = Convert.ToInt32(parts[1].Substring(1));
while (i < j)
{
result.Add(parts[0].Substring(0, 1) + i);
i++;
}
if (i == j)
{
result.Add(parts[0].Substring(0, 1) + i);
}
}
else
{
result.Add(parts[0]);
result.Add(parts[1]);
}
}
}
Console.WriteLine(string.Join(", ", result));
//output
D93, E93, E98, E9, E10, E26, D76, E76, D83, E83, D121, D122, D123, D124
The easiest way would be to use a combination of String.Split() and String.Join():
var result = String.Join(", ", s.Split(':', ' '));
Try string.Split
string input = "D93:E93 E98 E9:E10 E26 D76:E76 D83:E83 D121:D124";
var output = input.Split(new [] {':', ' '});
Console.WriteLine(output);
or if you need the commas:
string input = "D93:E93 E98 E9:E10 E26 D76:E76 D83:E83 D121:D124";
var output = input.Split(new [] {':', ' '});
var outstr = output.Aggregate((a,e) => a + ", " + e);
Console.WriteLine(outstr);

How to make a first letter capital in C#

How can the first letter in a text be set to capital?
Example:
it is a text. = It is a text.
public static string ToUpperFirstLetter(this string source)
{
if (string.IsNullOrEmpty(source))
return string.Empty;
// convert to char array of the string
char[] letters = source.ToCharArray();
// upper case the first char
letters[0] = char.ToUpper(letters[0]);
// return the array made of the new char array
return new string(letters);
}
It'll be something like this:
// precondition: before must not be an empty string
String after = before.Substring(0, 1).ToUpper() + before.Substring(1);
polygenelubricants' answer is fine for most cases, but you potentially need to think about cultural issues. Do you want this capitalized in a culture-invariant way, in the current culture, or a specific culture? It can make a big difference in Turkey, for example. So you may want to consider:
CultureInfo culture = ...;
text = char.ToUpper(text[0], culture) + text.Substring(1);
or if you prefer methods on String:
CultureInfo culture = ...;
text = text.Substring(0, 1).ToUpper(culture) + text.Substring(1);
where culture might be CultureInfo.InvariantCulture, or the current culture etc.
For more on this problem, see the Turkey Test.
If you are using C# then try this code:
Microsoft.VisualBasic.StrConv(sourceString, Microsoft.VisualBasic.vbProperCase)
I use this variant:
private string FirstLetterCapital(string str)
{
return Char.ToUpper(str[0]) + str.Remove(0, 1);
}
If you are sure that str variable is valid (never an empty-string or null), try:
str = Char.ToUpper(str[0]) + str[1..];
Unlike the other solutions that use Substring, this one does not do additional string allocations. This example basically concatenates char with ReadOnlySpan<char>.
I realize this is an old post, but I recently had this problem and solved it with the following method.
private string capSentences(string str)
{
string s = "";
if (str[str.Length - 1] == '.')
str = str.Remove(str.Length - 1, 1);
char[] delim = { '.' };
string[] tokens = str.Split(delim);
for (int i = 0; i < tokens.Length; i++)
{
tokens[i] = tokens[i].Trim();
tokens[i] = char.ToUpper(tokens[i][0]) + tokens[i].Substring(1);
s += tokens[i] + ". ";
}
return s;
}
In the sample below clicking on the button executes this simple code outBox.Text = capSentences(inBox.Text.Trim()); which pulls the text from the upper box and puts it in the lower box after the above method runs on it.
Take the first letter out of the word and then extract it to the other string.
strFirstLetter = strWord.Substring(0, 1).ToUpper();
strFullWord = strFirstLetter + strWord.Substring(1);
text = new String(
new [] { char.ToUpper(text.First()) }
.Concat(text.Skip(1))
.ToArray()
);
this functions makes capital the first letter of all words in a string
public static string FormatSentence(string source)
{
var words = source.Split(' ').Select(t => t.ToCharArray()).ToList();
words.ForEach(t =>
{
for (int i = 0; i < t.Length; i++)
{
t[i] = i.Equals(0) ? char.ToUpper(t[i]) : char.ToLower(t[i]);
}
});
return string.Join(" ", words.Select(t => new string(t)));;
}
string str = "it is a text";
// first use the .Trim() method to get rid of all the unnecessary space at the begining and the end for exemple (" This string ".Trim() is gonna output "This string").
str = str.Trim();
char theFirstLetter = str[0]; // this line is to take the first letter of the string at index 0.
theFirstLetter.ToUpper(); // .ToTupper() methode to uppercase the firstletter.
str = theFirstLetter + str.substring(1); // we add the first letter that we uppercased and add the rest of the string by using the str.substring(1) (str.substring(1) to skip the first letter at index 0 and only print the letters from the index 1 to the last index.)
Console.WriteLine(str); // now it should output "It is a text"
static String UppercaseWords(String BadName)
{
String FullName = "";
if (BadName != null)
{
String[] FullBadName = BadName.Split(' ');
foreach (string Name in FullBadName)
{
String SmallName = "";
if (Name.Length > 1)
{
SmallName = char.ToUpper(Name[0]) + Name.Substring(1).ToLower();
}
else
{
SmallName = Name.ToUpper();
}
FullName = FullName + " " + SmallName;
}
}
FullName = FullName.Trim();
FullName = FullName.TrimEnd();
FullName = FullName.TrimStart();
return FullName;
}
string Input = " it is my text";
Input = Input.TrimStart();
//Create a char array
char[] Letters = Input.ToCharArray();
//Make first letter a capital one
string First = char.ToUpper(Letters[0]).ToString();
//Concatenate
string Output = string.Concat(First,Input.Substring(1));
Try this code snippet:
char nm[] = "this is a test";
if(char.IsLower(nm[0])) nm[0] = char.ToUpper(nm[0]);
//print result: This is a test

Categories

Resources