string input = "\"Hello, World!\" ! \"Some other string\"";
Hello, I am having a problem with finding a solution to this. You see, I want to Split the string in half by the ! separating the two "fake strings" inside the string. I am aware that I can use String.Split(), but what if there is an exclamation mark inside the "fake string"?
Would appreciate if anyone could help.
You could use a regex: "(.*)" ! "(.*)"
https://regex101.com/r/4uBspp/1
Assuming the seperator will always be formed from the string \" ! \" you can use the Split overload function by passing that string as part of the string array.
string input = "\"Hello, World!\" ! \"Some other string\"";
var data = input.Split(new string[] { "\" ! \"" }, StringSplitOptions.None);
An alternative approach to the others is to use a state machine-style approach - if your start and end string delimiters were different (e.g. if they were < and > instead of ") then this would work better to support nested strings than a regex approach.
void Main()
{
var stateMachine = new StringSplitStateMachine();
stateMachine.Split("hi"); // hi
stateMachine.Split("hi!lo"); // hi, lo
stateMachine.Split("\"hi!lo\""); // "hi!lo"
stateMachine.Split("\"hi\"!lo"); // "hi", lo
}
public class StringSplitStateMachine
{
private readonly char _splitCharacter;
private readonly char _stringDelimiter;
public StringSplitStateMachine(char splitCharacter = '!', char stringDelimiter = '"')
{
_splitCharacter = splitCharacter;
_stringDelimiter = stringDelimiter;
}
public IEnumerable<string> Split(string input)
{
bool insideString =false;
var currentString = new StringBuilder();
foreach(var character in input)
{
if (character == _splitCharacter && !insideString)
{
yield return currentString.ToString();
currentString.Clear();
}
else
{
if (character == _stringDelimiter)
{
insideString = !insideString;
}
currentString.Append(character);
}
}
if (currentString.Length > 0)
{
yield return currentString.ToString();
}
}
}
Related
This question already has answers here:
How do I create a terminable while loop in console application?
(7 answers)
Closed 3 years ago.
I started a C# course now and there is an assignment where I have to create a "palindrome detector" program. Point is that user inputs some word or sentence, then I have to remove chars like ,.;:!? and space from it. I have done that with two different methods, because char method can not remove space so I wrote another method for it.
After "cleaning" operation program reversing input what user gave, and comparing original user input and reversed user input to each other. It they are same it prints "It is palindrome", if they are different it prints "It is not palindrome". That is working fine, BUT THE PROBLEM IS I have to put them in for loop. It have to ask input again and again, until user give empty.
This would be very easy, but somehow I can not do it.
Here is my code:
using System;
namespace Palindromi
{
class Program
{
static void Main()
{
Console.WriteLine("Hei! Tervetuloa palindromin tunnistusohjelmaan. Tämä tunnistaa, onko syöttämäsi sana sama toisinpäin!");
Console.Write("Anna teksti (tyhjä lopettaa): ");
string userinput = Console.ReadLine(); //userinput is user's input, this is what you have to modify. remove some chars and reverse it.
if (userinput == "")
{
Console.ReadLine();//when i have loop this have to be "break". This meant to break for loop when i have it.
}
char[] removechars = { '.', ':', ';', ',', '!', '?' };//this is the list of "have to be removed" chars
string userinput_without_chars = userinput.Trim(removechars); //this method remove chars which are listed
string userinput_without_chars_space = userinput_without_chars.Replace( " ", ""); //replace space with empty
string reverse_string, reversed;
reverse_string = userinput_without_chars_space;
reversed = "";
int len;
len = userinput_without_chars_space.Length - 1;
while (len >= 0)
{
reversed = reversed + reverse_string[len];
len--;
}
Console.WriteLine("Sana käännettynä on {0}", reversed); //tells user input reversed
if (userinput_without_chars_space == reversed)//check is the userinput same than reversed user input
{
Console.Write("On palindromi.");//it is palindrome
}
else
{
Console.Write("Ei ole palindromi.");//it is not palindrome
}
}
}
}
You could potentially do something along these lines:
var running = true;
while(running)
{
var input = Console.ReadLine().ToLower();
var phrase = input.Sanitize(new List<string>() {".", ",", "?", "!", "'", "&", "%", "$", " "});
if(phrase.IsPalindrome())
Console.Writeline("Input was palindrome.");
}
public static string Sanitize(this string input, IList<string> punctuation) =>
String.Join(String.Empty, input.Where(character => punctuation.Contains(character) == false));
public static bool IsPalindrome(this string sentence)
{
for (int l = 0, r = sentence.Length - 1; l < r; l++, r--)
if (sentence[l] != sentence[r])
return false;
return true;
}
public static void Close(string input)
{
// Some logic to see if the application should stop.
}
You could create another method that looks for commands, or keystrokes, then sets the boolean to run as false. Which would break the infinite loop. You could also do an abrupt close with Environment.Exit.
The very simplest approach is replace your Console.ReadLine() where you want to break to return.
Alternatively, you could wrap the logic in another while loop.
while (userinput != "")
{
// Remove chars
// rest of your logic
/* IMPORTANT */
userinput = Console.Readline();
}
To remove the symbols from the input, you can use the Regex.Replace method. In this case, you can be sure, that the specified symbols will be correctly removed from the input string. Note, that you can handle the whitespaces along with other characters you mentioned, like in the code snippet below:
var CharactersToRemove { get; set; } = " ,.;:!?";
var processedInput = Regex.Replace(input.ToLower(), $"[{CharactersToRemove}]", string.Empty);
Note, that here I used input.ToLower() to convert the input to a lowercase string. This will make the palindrome tests case-insensitive. Should you need case-sensitive palindrome tests, just remove the .ToLower() part.
There is no need to reverse the input string to check if it is a palindrome. You can check this within one for loop as follows:
bool CheckForBeingaAPalindrome(string input)
{
var frontIndex = 0;
var tailIndex = input.Length - 1;
for (; frontIndex < tailIndex;)
{
if (input[frontIndex] != input[tailIndex])
return false;
++frontIndex;
--tailIndex;
}
return true;
}
Note, that in this case you only iterate over the elements of the input string once. This approach will give you al least 4 times better performance than the one you used.
Below, you can find a complete minimal working solution to your problem.
using System.Text.RegularExpressions;
using static System.Console;
namespace Assignment
{
public static class PalindromeFinder
{
public static string CharactersToRemove { get; set; } = " ,.;:!?";
public static bool IsPalindrome(string input)
{
var processedInput = RemoveUnnecessaryCharacters(input);
return CheckForBeingAPalindrome(processedInput);
}
private static string RemoveUnnecessaryCharacters(string input)
{
return Regex.Replace(input.ToLower(), $"[{CharactersToRemove}]", string.Empty);
}
private static bool CheckForBeingAPalindrome(string input)
{
var frontIndex = 0;
var tailIndex = input.Length - 1;
for (; frontIndex < tailIndex;)
{
if (input[frontIndex] != input[tailIndex])
return false;
++frontIndex;
--tailIndex;
}
return true;
}
}
public class Program
{
private static void Main(string[] args)
{
ContinuouslyCheckUserInputForBeingAPalindrome();
}
private static void ContinuouslyCheckUserInputForBeingAPalindrome()
{
while (FetchUserInputFromConsole() is string input
&& !string.IsNullOrWhiteSpace(input))
{
var isPalindrome = PalindromeFinder.IsPalindrome(input);
var modifier = isPalindrome ? "a" : "not a";
WriteLine($"It is {modifier} palindrome");
}
}
private static string FetchUserInputFromConsole()
{
Write("Enter a string: ");
return ReadLine();
}
}
}
Lets say I have this string:
string text = "Hi my name is <crazy> Bob";
I want to take away everything within the brackets so it turns out like this:
"Hi my name is Bob".
So for I've tried with this and I know I've been think wrong with the while-loop but I just can't figure it out.
public static string Remove(string text)
{
char[] result = new char[text.Length];
for (int i = 0; i < text.Length; i++ )
{
if (text[i] == '<')
{
while (text[i] != '>')
{
result[i] += text[i];
}
}
else
{
result[i] += text[i];
}
}
return result.ToString();
}
Try this Regex:
public static string Remove(string text)
{
return Regex.Replace(text, "<.*?>","");
}
Look at this loop:
while (text[i] != '>')
{
result[i] += text[i];
}
That will continue executing until the condition isn't met. Given that you're not changing text[i], it's never going to stop...
Additionally, you're calling ToString on a char[] which isn't going to do what you want, and even if it did you'd have left-over characters.
If you wanted to loop like this, I'd use a StringBuilder, and just keep track of whether you're "in" an angle bracket or not:
public static string RemoveAngleBracketedContent(string text)
{
var builder = new StringBuilder();
int depth = 0;
foreach (var character in text)
{
if (character == '<')
{
depth++;
}
else if (character == '>' && depth > 0)
{
depth--;
}
else if (depth == 0)
{
builder.Append(character);
}
}
return builder.ToString();
}
Alternatively, use a regular expression. It would be relatively tricky to get it to cope with nested angle brackets, but if you don't need that, it's really simple:
// You can reuse this every time
private static Regex AngleBracketPattern = new Regex("<[^>]*>");
...
text = AngleBracketPattern.Replace(text, "");
One last problem though - after removing the angle-bracketed-text from "Hi my name is <crazy> Bob" you actually get "Hi my name is Bob" - note the double space.
use
string text = "Hi my name is <crazy> Bob";
text = System.Text.RegularExpressions.Regex.Replace(text, "<.*?>",string.Empty);
I recommend regex.
public static string DoIt(string content, string from, string to)
{
string regex = $"(\\{from})(.*)(\\{to})";
return Regex.Replace(content, regex, "");
}
For instance:
c:\dir1 c:\dir2 "c:\my files" c:\code "old photos" "new photos"
Should be read as a list:
c:\dir1
c:\dir2
c:\my files
c:\code
old photos
new photos
I can write a function which parses the string linearly but wondered if the .NET 2.0 toolbox has any cool tricks one could use?
Since you have to hit every character I think a brute force is going to give you the best performance.
That way you hit every character exactly once.
And it limits the number of comparisons performed.
static void Main(string[] args)
{
string input = #"c:\dir1 c:\dir2 ""c:\my files"" c:\code ""old photos"" ""new photos""";
List<string> splitInput = MySplit(input);
foreach (string s in splitInput)
{
System.Diagnostics.Debug.WriteLine(s);
}
System.Diagnostics.Debug.WriteLine(input);
}
public static List<string> MySplit(string input)
{
List<string> split = new List<string>();
StringBuilder sb = new StringBuilder();
bool splitOnQuote = false;
char quote = '"';
char space = ' ';
foreach (char c in input.ToCharArray())
{
if (splitOnQuote)
{
if (c == quote)
{
if (sb.Length > 0)
{
split.Add(sb.ToString());
sb.Clear();
}
splitOnQuote = false;
}
else { sb.Append(c); }
}
else
{
if (c == space)
{
if (sb.Length > 0)
{
split.Add(sb.ToString());
sb.Clear();
}
}
else if (c == quote)
{
if (sb.Length > 0)
{
split.Add(sb.ToString());
sb.Clear();
}
splitOnQuote = true;
}
else { sb.Append(c); }
}
}
if (sb.Length > 0) split.Add(sb.ToString());
return split;
}
Usually for this type of problem one could develop a regular expression to parse out the fields. ( "(.*?)" ) would give you all the string values in quotes. You could strip all those values from your string, and then do a simple split on space after all the quoted items are out.
static void Main(string[] args)
{
string myString = "\"test\" test1 \"test2 test3\" test4 test6 \"test5\"";
string myRegularExpression = #"""(.*?)""";
List<string> listOfMatches = new List<string>();
myString = Regex.Replace(myString, myRegularExpression, delegate(Match match)
{
string v = match.ToString();
listOfMatches.Add(v);
return "";
});
var array = myString.Split(' ');
foreach (string s in array)
{
if(s.Trim().Length > 0)
listOfMatches.Add(s);
}
foreach (string match in listOfMatches)
{
Console.WriteLine(match);
}
Console.Read();
}
Unfortunately, I don't think there is any sort of C# kungfu that makes it much simpler. I should add that obviously, this algorithm gives you the items out of order... so if that matters... this isn't a good solution.
Here's a regex-only solution which captures both space-delimited and quoted paths. Quoted paths are stripped of the quotes, multiple spaces don't cause empty list entries. Edge case of mixing a quoted path with a non-quoted path without intervening space is interpreted as multiple entries.
It can be optimized by disabling captures for unused groups but I opted for more readability instead.
static Regex re = new Regex(#"^([ ]*((?<r>[^ ""]+)|[""](?<r>[^""]*)[""]))*[ ]*$");
public static IEnumerable<string> RegexSplit(string input)
{
var m = re.Match(input ?? "");
if(!m.Success)
throw new ArgumentException("Malformed input.");
return from Capture capture in m.Groups["r"].Captures select capture.Value;
}
Assuming that a space acts as a delimiter between except when enclosed in quotes (to allow paths to contain spaces), I'd recommend the following algorithm:
ignore_space = false;
i = 0;
list_of_breaks=[];
while(i < input_length)
{
if(charat(i) is a space and ignore_space is false)
{
add i to list_of_breaks;
}
else if(charat(i) is a quote)
{
ignore_space = ! ignore_space
}
}
split the input at the indices listed in list_of_breaks
I have a string like this;
string text = "6A7FEBFCCC51268FBFF";
And I have one method for which I want to insert the logic for appending the hyphen after 4 characters to 'text' variable. So, the output should be like this;
6A7F-EBFC-CC51-268F-BFF
Appending hyphen to above 'text' variable logic should be inside this method;
public void GetResultsWithHyphen
{
// append hyphen after 4 characters logic goes here
}
And I want also remove the hyphen from a given string such as 6A7F-EBFC-CC51-268F-BFF. So, removing hyphen from a string logic should be inside this method;
public void GetResultsWithOutHyphen
{
// Removing hyphen after 4 characters logic goes here
}
How can I do this in C# (for desktop app)?
What is the best way to do this?
Appreciate everyone's answer in advance.
GetResultsWithOutHyphen is easy (and should return a string instead of void
public string GetResultsWithOutHyphen(string input)
{
// Removing hyphen after 4 characters logic goes here
return input.Replace("-", "");
}
for GetResultsWithHyphen, there may be slicker ways to do it, but here's one way:
public string GetResultsWithHyphen(string input)
{
// append hyphen after 4 characters logic goes here
string output = "";
int start = 0;
while (start < input.Length)
{
output += input.Substring(start, Math.Min(4,input.Length - start)) + "-";
start += 4;
}
// remove the trailing dash
return output.Trim('-');
}
Use regex:
public String GetResultsWithHyphen(String inputString)
{
return Regex.Replace(inputString, #"(\w{4})(\w{4})(\w{4})(\w{4})(\w{3})",
#"$1-$2-$3-$4-$5");
}
and for removal:
public String GetResultsWithOutHyphen(String inputString)
{
return inputString.Replace("-", "");
}
Here's the shortest regex I could come up with. It will work on strings of any length. Note that the \B token will prevent it from matching at the end of a string, so you don't have to trim off an extra hyphen as with some answers above.
using System;
using System.Text.RegularExpressions;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
string text = "6A7FEBFCCC51268FBFF";
for (int i = 0; i <= text.Length;i++ )
Console.WriteLine(hyphenate(text.Substring(0, i)));
}
static string hyphenate(string s)
{
var re = new Regex(#"(\w{4}\B)");
return re.Replace (s, "$1-");
}
static string dehyphenate (string s)
{
return s.Replace("-", "");
}
}
}
var hyphenText = new string(
text
.SelectMany((i, ch) => i%4 == 3 && i != text.Length-1 ? new[]{ch, '-'} : new[]{ch})
.ToArray()
)
something along the lines of:
public string GetResultsWithHyphen(string inText)
{
var counter = 0;
var outString = string.Empty;
while (counter < inText.Length)
{
if (counter % 4 == 0)
outString = string.Format("{0}-{1}", outString, inText.Substring(counter, 1));
else
outString += inText.Substring(counter, 1);
counter++;
}
return outString;
}
This is rough code and may not be perfectly, syntactically correct
public static string GetResultsWithHyphen(string str) {
return Regex.Replace(str, "(.{4})", "$1-");
//if you don't want trailing -
//return Regex.Replace(str, "(.{4})(?!$)", "$1-");
}
public static string GetResultsWithOutHyphen(string str) {
//if you just want to remove the hyphens:
//return input.Replace("-", "");
//if you REALLY want to remove hyphens only if they occur after 4 places:
return Regex.Replace(str, "(.{4})-", "$1");
}
For removing:
String textHyphenRemoved=text.Replace('-',''); should remove all of the hyphens
for adding
StringBuilder strBuilder = new StringBuilder();
int startPos = 0;
for (int i = 0; i < text.Length / 4; i++)
{
startPos = i * 4;
strBuilder.Append(text.Substring(startPos,4));
//if it isn't the end of the string add a hyphen
if(text.Length-startPos!=4)
strBuilder.Append("-");
}
//add what is left
strBuilder.Append(text.Substring(startPos, 4));
string textWithHyphens = strBuilder.ToString();
Do note that my adding code is untested.
GetResultsWithOutHyphen method
public string GetResultsWithOutHyphen(string input)
{
return input.Replace("-", "");
}
GetResultsWithOutHyphen method
You could pass a variable instead of four for flexibility.
public string GetResultsWithHyphen(string input)
{
string output = "";
int start = 0;
while (start < input.Length)
{
char bla = input[start];
output += bla;
start += 1;
if (start % 4 == 0)
{
output += "-";
}
}
return output;
}
This worked for me when I had a value for a social security number (123456789) and needed it to display as (123-45-6789) in a listbox.
ListBox1.Items.Add("SS Number : " & vbTab & Format(SSNArray(i), "###-##-####"))
In this case I had an array of Social Security Numbers. This line of code alters the formatting to put a hyphen in.
Callee
public static void Main()
{
var text = new Text("THISisJUSTanEXAMPLEtext");
var convertText = text.Convert();
Console.WriteLine(convertText);
}
Caller
public class Text
{
private string _text;
private int _jumpNo = 4;
public Text(string text)
{
_text = text;
}
public Text(string text, int jumpNo)
{
_text = text;
_jumpNo = jumpNo < 1 ? _jumpNo : jumpNo;
}
public string Convert()
{
if (string.IsNullOrEmpty(_text))
{
return string.Empty;
}
if (_text.Length < _jumpNo)
{
return _text;
}
var convertText = _text.Substring(0, _jumpNo);
int start = _jumpNo;
while (start < _text.Length)
{
convertText += "-" + _text.Substring(start, Math.Min(_jumpNo, _text.Length - start));
start += _jumpNo;
}
return convertText;
}
}
I have a URL formatter in my application but the problem is that the customer wants to be able to enter special characters like:
: | / - “ ‘ & * # #
I have a string:
string myCrazyString = ":|/-\“‘&*##";
I have a function where another string is being passed:
public void CleanMyString(string myStr)
{
}
How can I compare the string being passed "myStr" to "myCrazyString" and if "myStr has any of the characters in myCrazyString to remove it?
So if I pass to my function:
"this ' is a" cra#zy: me|ssage/ an-d I& want#to clea*n it"
It should return:
"this is a crazy message and I want to clean it"
How can I do this in my CleanMyString function?
Use Regular Expression for that Like:
pattern = #"(:|\||\/|\-|\\|\“|\‘|\&|\*|\#|\#)";
System.Text.RegularExpressions.Regex.Replace(inputString, pattern, string.Empty);
split each string you want to remove by |
To remove the special characters like the | itself use \, so \| this will handle the | as normal character.
Test:
inputString = #"H\I t&he|r#e!";
//output is: HI there!
solution without regular expressions, just for availability purposes:
static string clear(string input)
{
string charsToBeCleared = ":|/-\“‘&*##";
string output = "";
foreach (char c in input)
{
if (charsToBeCleared.IndexOf(c) < 0)
{
output += c;
}
}
return output;
}
You can use Regex as others mentioned, or code like this:
char[] myCrazyChars = "\"\':|/-\\“‘&*##".ToCharArray();
string myCrazyString = "this ' is a\" cra#zy: me|ssage/ an-d I& want#to clea*n it";
string[] splittedCrazyString = myCrazyString.Split(myCrazyChars);
string notCrazyStringAtAll = string.Join("", splittedCrazyString);
Try using a Regular Expression.
Here's a fairly straight-forward way to do it. Split the string based on all of the characters in your "crazy string and then join them back together without the bad characters.
string myCrazyString = #":|/-\“‘&*##";
string str = #"this ' is a"" cra#zy: me|ssage/ an-d I& want#to clea*n it";
string[] arr = str.Split(myCrazyString.ToCharArray(), StringSplitOptions.None);
str = string.Join(string.Empty, arr);
Another possible solution:
namespace RemoveChars
{
class Program
{
static string str = #"this ' is a\“ cra#zy: me|ssage/ an-d I& want#to clea*n it";
static void Main(string[] args)
{
CleanMyString(str);
}
public static void CleanMyString(string myStr)
{
string myCrazyString = #":|/-\“‘&*##";
var result = "";
foreach (char c in myStr)
{
var t = true; // t will remain true if c is not a crazy char
foreach (char ch in myCrazyString)
if (c == ch)
{
t = false;
break;
}
if (t)
result += c;
}
}
}
}
You could try an if statement and if a character is present then mention the craziness
if (myCrazyString.Contains("#"))
{
Console.WriteLine("This string is out of controL!");
}
Regex is also a good idea(Maybe better)
Try this :
1.Define a StringBuilder
2.Iterate through the characters of the string to be cleaned.
3.Put everything required in the StringBuilder and ignore other special charactersby simply putting if conditions.
4.Rerurn StringBuilder.
Or
Try using Regular Expression.