How would I remove all whitespaces in a string but keep whitespaces in between "", here's a example.
I need
string idk = "Stackoverflow is a very \"helpful website to\" use";
To be
string idk = "Stackoverflowisavery\"helpful website to\"use";
CodePudding user response:
Got it!
const string s = @"This is a ""quoted string""... or so I've been told...";
StringBuilder sb = new StringBuilder();
var quoteActive = false;
foreach (char c in s)
{
if (c == '"')
{
quoteActive = !quoteActive;
}
else if (c != ' ' || quoteActive)
{
sb.Append(c);
}
}
CodePudding user response:
Upfront warning - I would recommend you consider carefully whether you would use this answer in a production system, because it's probably difficult for many to quickly grok how it works, as it uses features of C# that are seldom encountered. It's a great opportunity to talk about those features and give a reminder about their existence though
As an idle curio , here's a LINQ equivalent to what you have already
var b = false;
var t = s.Aggregate(new StringBuilder(), (sb, c) => ((b^=c=='"')||c!=' ') ? sb.Append(c) : sb);
It shortens the logic of the ifs to ((b^=c=='"')||c!=' ')
, to explain this it's probably worth picking it apart. Let's just look at the (b^=c=='"')
part, aand see what it returns, for each char in the string:
var s = " hello world \" this is \" a string";
var b = false;
foreach(char c in s){
Console.WriteLine(c " " (b^=c=='"'));
}
Prints:
False
h False
e False
l False
l False
o False
False
w False
o False
r False
l False
d False
False
" True
True
t True
h True
i True
s True
True
i True
s True
True
" False
False
a False
False
s False
t False
r False
i False
n False
g False
(b^=c=='"')
expands to (b = b ^ c=='"')
=> "b is xor of itself and 'c is quote')
The use of XOR on the bool effectively causes the boolean B to toggle every time a quote is encountered. Because every assignment operation in C# returns a value, usually the result of the assignment, it means we can use the new value of b
in a further test.
We are trying to work out "do we want to add the char or not?". In the above, the True are sorted - inside of a "..." we always want to add the char. Outside of a "..." we only want to add a char if it is NOT a space, hence adding ||c!=' '
foreach(char c in s){
Console.WriteLine(c " " ((b^=c=='"')||c!=' ')) ;
}
Prints
False
h True
e True
l True
l True
o True
False
w True
o True
r True
l True
d True
False
" True
True
t True
h True
i True
s True
True
i True
s True
True
" True
False
a True
False
s True
t True
r True
i True
n True
g True
So now, everything that is "true" is "wanted", and everything that is "false" is "not wanted". This means a simple ternary will suffice for the aggregate: stringbuilder helpfully returns itself after an append, so if we do want to add a char, then sb.Append(char)
adds the char and returns the stringbuilder
(sb, c) => ((b^=c=='"')||c!=' ') ? sb.Append(c) : sb
Is therefore a lambda that takes a stringbuilder and a char, and returns a stringbuilder, just like Aggregate demands
You could also use this form in a classic loop
foreach(char c in s)
if((b^=c=='"')||c!=' '))
sb.Append(c);
Would you actually use it in production code? Personally I think that massively depends on whether the next person after you will read it and go "oh yeah!" rather than "WTF". Tanveer has pointed out in the comments that any code that takes vastly more time to work out/explain than to write is potentially problematic in this regard, and it's a worthy point; if this style of code appeals to you and your colleagues then great. If not, go for something that's more "can understand it at a glance"
I personally wouldn't use code with a high WTF-factor, but it was a fun exercise/reminder of XOR and using assignment-returned values in the context of needing a single-statement expression
CodePudding user response:
You can use:
string idk = "Stackoverflow is a very \"helpful website to\" use";
idk = idk.Replace(" ", "");
Console.WriteLine(idk);
// prints message with removed whitespace