The code works well now. Fell free to use it if you need it.
Problem:
To write a console application that translates a text from gibberish into Romanian. The gibberish language is similar to Romanian. A Romanian text is written in gibberish by taking the original text and inserting after each vowel the letter p and the corresponding vowel.
Example:
For input data:
Apanapa aparepe meperepe.
At the console it will show:
Ana are mere
Here is my code:
using System;
using System.Text;
namespace FromGibberishUgly
{
class Program
{
private static string GibberishToRomanian(string text)
{
if (null == text)
return "";
const string vowels = "aeiouAEIOU";
StringBuilder sb = new StringBuilder(text.Length);
for (int i = 0; i < text.Length; ++i)
{
sb.Append(text[i]);
if (i < text.Length - 2 &&
vowels.Contains(text[i]) &&
text[i + 1] == 'p' &&
char.ToLower(text[i + 2]) == char.ToLower(text[i]))
i += 2;
}
return sb.ToString();
}
static void Main(string[] args)
{
Console.WriteLine(GibberishToRomanian(Console.ReadLine()));
}
}
}
When having a simple pattern (vowel + p + vowel in your case) you can try using regular expressions:
using System.Text.RegularExpressions;
...
private static string GibberishToRomanian(string text) =>
Regex.Replace(text ?? "", #"([aeiou])p\1", "$1", RegexOptions.IgnoreCase);
Demo:
Console.Write(GibberishToRomanian("Apanapa aparepe meperepe"));
Outcome:
Ana are mere
Pattern explained:
([aeiou]) - capturing group #1 for any vowel
p - letter 'p'
\1 - value captured by group #1
Edit: If you want to stick to loops, you can try put it like this:
private static string GibberishToRomanian(string text) {
if (null == text)
return "";
const string vowels = "aeiouAEIOU";
StringBuilder sb = new StringBuilder(text.Length);
for (int i = 0; i < text.Length; ++i) {
sb.Append(text[i]);
// when facing vowel + p + vowel we jump over p + vowel
if (i < text.Length - 2 &&
vowels.Contains(text[i]) &&
text[i + 1] == 'p' &&
char.ToLower(text[i + 2]) == char.ToLower(text[i]))
i += 2;
}
return sb.ToString();
}
The program will be (fiddle)
using System;
using System.Text;
using System.Text.RegularExpressions;
namespace FromGibberishUgly {
class Program {
//TODO: or replace it with loop solution
private static string GibberishToRomanian(string text) =>
Regex.Replace(text ?? "", #"([aeiou])p\1", "$1", RegexOptions.IgnoreCase);
static void Main(string[] args) {
Console.WriteLine(GibberishToRomanian(Console.ReadLine()));
}
}
}
Is it possible to remove every occurance of a character + one after it from entire string?
Here's a code that achieves what I described, but is rather big:
private static string FilterText(string text){
string filteredText = text;
while (true)
{
int comaIndex = filteredText.IndexOf('.');
if (comaIndex == -1)
{
break;
}
else if (comaIndex > 1)
{
filteredText = filteredText.Substring(0, comaIndex) + filteredText.Substring(comaIndex + 2);
}
else if (comaIndex == 1)
{
filteredText = filteredText[0] + filteredText.Substring(comaIndex + 2);
}
else
{
filteredText = filteredText.Substring(comaIndex + 2);
}
}
return filteredText;
}
This code would turn for example input .Otest.1 .2.,string.w.. to test string
Is it possible to achieve the same result using regex?
You want to use
var output = Regex.Replace(text, #"\..", RegexOptions.Singleline);
See the .NET regex demo. Details:
\. - matches a dot
. - matches any char including a line feed char due to the RegexOptions.Singleline option used.
Try this pattern: (?<!\.)\w+
code:
using System;
using System.Text.RegularExpressions;
public class Test{
public static void Main(){
string str = ".Otest.1 .2.,string.w..";
Console.WriteLine(FilterText(str));
}
private static string FilterText(string text){
string pattern = #"(?<!\.)\w+";
string result = "";
foreach(Match m in Regex.Matches(text, pattern)){
result += m + " ";
}
return result;
}
}
output:
test string
The task is to read from a file, retrieve words (no numbers or special characters) and adding it to a hash table. If the same word (key) already exist in the hash table, update the frequency of the word(value) +1.
So far in the code blow, all text is retrieved from the file including words with numbers and special characters into a string array "words".
I would like to update the values based on a regex to only keep words with letters, in lowercase.
I have tried the regex in all different ways but it does not work. The Split() method only allows individual characters to be removed. (eventually, this code will need to be applied to 200 files with unknown amount of special characters and numbers).
Is there a clean way to read the file, save only words and omit special characters and numbers?
this is what i have so far:
using System;
using System.Collections.Generic;
using System.Collections;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text.RegularExpressions;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
String myLine;
String[] words;
Hashtable hashT = new Hashtable();
TextReader tr = new StreamReader("C:\\file including numbers and spacial charecters.txt");
while ((myLine = tr.ReadLine()) != null)
{
words = myLine.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
string pattern = #"^[a - z] +$";
Regex term = new Regex(pattern);
for (int i = 0; i < words.Length; i++)
{
Console.WriteLine(words[i]);
words[i] = Regex.Replace(words[i], term, "");
if (hashT.ContainsKey(words[0]))
{
hashT[words[i]] = double.Parse(hashT[words[i]].ToString()) + 1;
}
else
{
hashT.Add(words[i], 1.00);
}
}
foreach (String word in hashT.Keys)
{
Console.WriteLine(word + " " + hashT[words]);
}
Console.ReadKey();
}
}
}
}
try this
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
//file content read form your file
string fileContent = #"Hello Wor1d
fun f1nd found
";
//split file content to lines
string[] line = fileContent.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
Regex r = new Regex("[a-zA-Z]+");
List<string> matchesList = new List<string>();
for (int i = 0; i < line.Length; i++)
{
//split line to string, like Hello Wor1d => string[]{ Hello, Wor1d }
string[] lineData = line[i].Split(' ');
for (int j = 0; j < lineData.Length; j++)
{
string str = lineData[j];
//get matches form string
//if count == 0, string is not include words
//if count > 1 string is have some not words, because Wor1d have 2 matches => Wor and d
if (r.Matches(str).Count == 1)
{
matchesList.Add(str);
}
}
}
for (int i = 0; i < matchesList.Count; i++)
{
Console.WriteLine($"{matchesList[i]} is ok");
}
Console.ReadLine();
}
}
}
I have strings that look like the following:
"1y 250 2y 32% 3y otherjibberish".
My ultimate goal is to split it into the following:
"1y 250"
"2y 32%"
"3y otherjibberish"
The main 'separator' between these splits are the "\d+y" patterns. Using Regex (C# 4.0), I can use the Matches function to match a number followed by a 'y', but I don't know how to get everything that follows that match but precedes the next match.
Is there a way to do that?
Hopefully that makes sense.... Much appreciated
- kcross
You can use a "MatchCollection" to split the string according to the occurrences.
The example below does almost what you want. The blank character at right of each string is not removed.
Code:
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
namespace Q11438740ConApp
{
class Program
{
static void Main(string[] args)
{
string sourceStr = "1y 250 2y 32% 3y otherjibberish";
Regex rx = new Regex(#"\d+y");
string[] splitedArray = SplitByRegex(sourceStr, rx);
for (int i = 0; i < splitedArray.Length; i++)
{
Console.WriteLine(String.Format("'{0}'", splitedArray[i]));
}
Console.ReadLine();
}
public static string[] SplitByRegex(string input, Regex rx)
{
MatchCollection matches = rx.Matches(input);
String[] outArray = new string[matches.Count];
for (int i = 0; i < matches.Count; i++)
{
int length = 0;
if (i == matches.Count - 1)
{
length = input.Length - (matches[i].Index + matches[i].Length);
}
else
{
length = matches[i + 1].Index - (matches[i].Index + matches[i].Length);
}
outArray[i] = matches[i].Value + input.Substring(matches[i].Index + matches[i].Length, length);
}
return outArray;
}
}
}
Output:
'1y 250 '
'2y 32% '
'3y otherjibberish'
"Solution" 7z file: Q11438740ConApp.7z
This was actually quite easy... Just used the Regex.Split() method.
What is the best way to convert from Pascal Case (upper Camel Case) to a sentence.
For example starting with
"AwaitingFeedback"
and converting that to
"Awaiting feedback"
C# preferable but I could convert it from Java or similar.
public static string ToSentenceCase(this string str)
{
return Regex.Replace(str, "[a-z][A-Z]", m => m.Value[0] + " " + char.ToLower(m.Value[1]));
}
In versions of visual studio after 2015, you can do
public static string ToSentenceCase(this string str)
{
return Regex.Replace(str, "[a-z][A-Z]", m => $"{m.Value[0]} {char.ToLower(m.Value[1])}");
}
Based on: Converting Pascal case to sentences using regular expression
I will prefer to use Humanizer for this. Humanizer is a Portable Class Library that meets all your .NET needs for manipulating and displaying strings, enums, dates, times, timespans, numbers and quantities.
Short Answer
"AwaitingFeedback".Humanize() => Awaiting feedback
Long and Descriptive Answer
Humanizer can do a lot more work other examples are:
"PascalCaseInputStringIsTurnedIntoSentence".Humanize() => "Pascal case input string is turned into sentence"
"Underscored_input_string_is_turned_into_sentence".Humanize() => "Underscored input string is turned into sentence"
"Can_return_title_Case".Humanize(LetterCasing.Title) => "Can Return Title Case"
"CanReturnLowerCase".Humanize(LetterCasing.LowerCase) => "can return lower case"
Complete code is :
using Humanizer;
using static System.Console;
namespace HumanizerConsoleApp
{
class Program
{
static void Main(string[] args)
{
WriteLine("AwaitingFeedback".Humanize());
WriteLine("PascalCaseInputStringIsTurnedIntoSentence".Humanize());
WriteLine("Underscored_input_string_is_turned_into_sentence".Humanize());
WriteLine("Can_return_title_Case".Humanize(LetterCasing.Title));
WriteLine("CanReturnLowerCase".Humanize(LetterCasing.LowerCase));
}
}
}
Output
Awaiting feedback
Pascal case input string is turned into sentence
Underscored input string is turned into sentence Can Return Title Case
can return lower case
If you prefer to write your own C# code you can achieve this by writing some C# code stuff as answered by others already.
Here you go...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CamelCaseToString
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(CamelCaseToString("ThisIsYourMasterCallingYou"));
}
private static string CamelCaseToString(string str)
{
if (str == null || str.Length == 0)
return null;
StringBuilder retVal = new StringBuilder(32);
retVal.Append(char.ToUpper(str[0]));
for (int i = 1; i < str.Length; i++ )
{
if (char.IsLower(str[i]))
{
retVal.Append(str[i]);
}
else
{
retVal.Append(" ");
retVal.Append(char.ToLower(str[i]));
}
}
return retVal.ToString();
}
}
}
This works for me:
Regex.Replace(strIn, "([A-Z]{1,2}|[0-9]+)", " $1").TrimStart()
This is just like #SSTA, but is more efficient than calling TrimStart.
Regex.Replace("ThisIsMyCapsDelimitedString", "(\\B[A-Z])", " $1")
Found this in the MvcContrib source, doesn't seem to be mentioned here yet.
return Regex.Replace(input, "([A-Z])", " $1", RegexOptions.Compiled).Trim();
Just because everyone has been using Regex (except this guy), here's an implementation with StringBuilder that was about 5x faster in my tests. Includes checking for numbers too.
"SomeBunchOfCamelCase2".FromCamelCaseToSentence == "Some Bunch Of Camel Case 2"
public static string FromCamelCaseToSentence(this string input) {
if(string.IsNullOrEmpty(input)) return input;
var sb = new StringBuilder();
// start with the first character -- consistent camelcase and pascal case
sb.Append(char.ToUpper(input[0]));
// march through the rest of it
for(var i = 1; i < input.Length; i++) {
// any time we hit an uppercase OR number, it's a new word
if(char.IsUpper(input[i]) || char.IsDigit(input[i])) sb.Append(' ');
// add regularly
sb.Append(input[i]);
}
return sb.ToString();
}
Here's a basic way of doing it that I came up with using Regex
public static string CamelCaseToSentence(this string value)
{
var sb = new StringBuilder();
var firstWord = true;
foreach (var match in Regex.Matches(value, "([A-Z][a-z]+)|[0-9]+"))
{
if (firstWord)
{
sb.Append(match.ToString());
firstWord = false;
}
else
{
sb.Append(" ");
sb.Append(match.ToString().ToLower());
}
}
return sb.ToString();
}
It will also split off numbers which I didn't specify but would be useful.
string camel = "MyCamelCaseString";
string s = Regex.Replace(camel, "([A-Z])", " $1").ToLower().Trim();
Console.WriteLine(s.Substring(0,1).ToUpper() + s.Substring(1));
Edit: didn't notice your casing requirements, modifed accordingly. You could use a matchevaluator to do the casing, but I think a substring is easier. You could also wrap it in a 2nd regex replace where you change the first character
"^\w"
to upper
\U (i think)
I'd use a regex, inserting a space before each upper case character, then lowering all the string.
string spacedString = System.Text.RegularExpressions.Regex.Replace(yourString, "\B([A-Z])", " \k");
spacedString = spacedString.ToLower();
It is easy to do in JavaScript (or PHP, etc.) where you can define a function in the replace call:
var camel = "AwaitingFeedbackDearMaster";
var sentence = camel.replace(/([A-Z].)/g, function (c) { return ' ' + c.toLowerCase(); });
alert(sentence);
Although I haven't solved the initial cap problem... :-)
Now, for the Java solution:
String ToSentence(String camel)
{
if (camel == null) return ""; // Or null...
String[] words = camel.split("(?=[A-Z])");
if (words == null) return "";
if (words.length == 1) return words[0];
StringBuilder sentence = new StringBuilder(camel.length());
if (words[0].length() > 0) // Just in case of camelCase instead of CamelCase
{
sentence.append(words[0] + " " + words[1].toLowerCase());
}
else
{
sentence.append(words[1]);
}
for (int i = 2; i < words.length; i++)
{
sentence.append(" " + words[i].toLowerCase());
}
return sentence.toString();
}
System.out.println(ToSentence("AwaitingAFeedbackDearMaster"));
System.out.println(ToSentence(null));
System.out.println(ToSentence(""));
System.out.println(ToSentence("A"));
System.out.println(ToSentence("Aaagh!"));
System.out.println(ToSentence("stackoverflow"));
System.out.println(ToSentence("disableGPS"));
System.out.println(ToSentence("Ahh89Boo"));
System.out.println(ToSentence("ABC"));
Note the trick to split the sentence without loosing any character...
Pseudo-code:
NewString = "";
Loop through every char of the string (skip the first one)
If char is upper-case ('A'-'Z')
NewString = NewString + ' ' + lowercase(char)
Else
NewString = NewString + char
Better ways can perhaps be done by using regex or by string replacement routines (replace 'X' with ' x')
An xquery solution that works for both UpperCamel and lowerCamel case:
To output sentence case (only the first character of the first word is capitalized):
declare function content:sentenceCase($string)
{
let $firstCharacter := substring($string, 1, 1)
let $remainingCharacters := substring-after($string, $firstCharacter)
return
concat(upper-case($firstCharacter),lower-case(replace($remainingCharacters, '([A-Z])', ' $1')))
};
To output title case (first character of each word capitalized):
declare function content:titleCase($string)
{
let $firstCharacter := substring($string, 1, 1)
let $remainingCharacters := substring-after($string, $firstCharacter)
return
concat(upper-case($firstCharacter),replace($remainingCharacters, '([A-Z])', ' $1'))
};
Found myself doing something similar, and I appreciate having a point-of-departure with this discussion. This is my solution, placed as an extension method to the string class in the context of a console application.
using System;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string piratese = "avastTharMatey";
string ivyese = "CheerioPipPip";
Console.WriteLine("{0}\n{1}\n", piratese.CamelCaseToString(), ivyese.CamelCaseToString());
Console.WriteLine("For Pete\'s sake, man, hit ENTER!");
string strExit = Console.ReadLine();
}
}
public static class StringExtension
{
public static string CamelCaseToString(this string str)
{
StringBuilder retVal = new StringBuilder(32);
if (!string.IsNullOrEmpty(str))
{
string strTrimmed = str.Trim();
if (!string.IsNullOrEmpty(strTrimmed))
{
retVal.Append(char.ToUpper(strTrimmed[0]));
if (strTrimmed.Length > 1)
{
for (int i = 1; i < strTrimmed.Length; i++)
{
if (char.IsUpper(strTrimmed[i])) retVal.Append(" ");
retVal.Append(char.ToLower(strTrimmed[i]));
}
}
}
}
return retVal.ToString();
}
}
}
Most of the preceding answers split acronyms and numbers, adding a space in front of each character. I wanted acronyms and numbers to be kept together so I have a simple state machine that emits a space every time the input transitions from one state to the other.
/// <summary>
/// Add a space before any capitalized letter (but not for a run of capitals or numbers)
/// </summary>
internal static string FromCamelCaseToSentence(string input)
{
if (string.IsNullOrEmpty(input)) return String.Empty;
var sb = new StringBuilder();
bool upper = true;
for (var i = 0; i < input.Length; i++)
{
bool isUpperOrDigit = char.IsUpper(input[i]) || char.IsDigit(input[i]);
// any time we transition to upper or digits, it's a new word
if (!upper && isUpperOrDigit)
{
sb.Append(' ');
}
sb.Append(input[i]);
upper = isUpperOrDigit;
}
return sb.ToString();
}
And here's some tests:
[TestCase(null, ExpectedResult = "")]
[TestCase("", ExpectedResult = "")]
[TestCase("ABC", ExpectedResult = "ABC")]
[TestCase("abc", ExpectedResult = "abc")]
[TestCase("camelCase", ExpectedResult = "camel Case")]
[TestCase("PascalCase", ExpectedResult = "Pascal Case")]
[TestCase("Pascal123", ExpectedResult = "Pascal 123")]
[TestCase("CustomerID", ExpectedResult = "Customer ID")]
[TestCase("CustomABC123", ExpectedResult = "Custom ABC123")]
public string CanSplitCamelCase(string input)
{
return FromCamelCaseToSentence(input);
}
Mostly already answered here
Small chage to the accepted answer, to convert the second and subsequent Capitalised letters to lower case, so change
if (char.IsUpper(text[i]))
newText.Append(' ');
newText.Append(text[i]);
to
if (char.IsUpper(text[i]))
{
newText.Append(' ');
newText.Append(char.ToLower(text[i]));
}
else
newText.Append(text[i]);
Here is my implementation. This is the fastest that I got while avoiding creating spaces for abbreviations.
public static string PascalCaseToSentence(string input)
{
if (string.IsNullOrEmpty(input) || input.Length < 2)
return input;
var sb = new char[input.Length + ((input.Length + 1) / 2)];
var len = 0;
var lastIsLower = false;
for (int i = 0; i < input.Length; i++)
{
var current = input[i];
if (current < 97)
{
if (lastIsLower)
{
sb[len] = ' ';
len++;
}
lastIsLower = false;
}
else
{
lastIsLower = true;
}
sb[len] = current;
len++;
}
return new string(sb, 0, len);
}