Reputation: 403
As part of the refactor I make to this code, I've come across this snippet of code and I'm debating what's more correct / efficient?
Before:
string CutHeadAndTail(string pattern)
{
if (pattern[0] == '*')
{
pattern = pattern.Substring(1);
}
if (pattern[pattern.Length - 1] == '*')
{
pattern = pattern.Substring(0, pattern.Length - 1);
}
return pattern;
}
After:
private string RemoveAllowedAstrisks(string pattern)
{
pattern = pattern[0] == '*'?pattern.Substring(1): pattern;
pattern = pattern[pattern.Length - 1] == '*' ? pattern.Substring(0, pattern.Length - 1) : pattern;
return pattern;
}
What's better?
I am thinking about the line pattern = pattern[0] == '*'?pattern.Substring(1): pattern;
Means, from readability point of view I prefer the second. But in the other hand, the meaning of this expression is the below two options:
pattern[0]=='*'
--> in such case pattern will changed to pattern.Substring(1)
else
--> pattern = pattern
While if I will choose the first way (ignoring the naming etc.) I have just the first option:
if (pattern[0] == '*')
{
pattern = pattern.Substring(1);
}
return pattern;
The bottom line: Does the line pattern = pattern
cost more memory?
Upvotes: 0
Views: 178
Reputation: 1991
How about the following: calculate whether to trim a character from either front or back or both, and if so, return a substring, otherwise return the string itself.
string CutHeadAndTail(string pattern)
{
var s = pattern[0] == '*' ? 1 : 0;
var e = pattern[pattern.Length - 1] == '*' ? 1 : 0;
return (s > 0 || e > 0) ?
pattern.Substring(s, pattern.Length - s - e) :
pattern;
}
Upvotes: 0
Reputation: 39072
I have checked the generated IL code to see what is created.
IL_000e: ldloc.0 // hello
IL_000f: ldc.i4.0
IL_0010: callvirt instance char [mscorlib]System.String::get_Chars(int32)
IL_0015: ldc.i4.s 42 // 0x2a
IL_0017: beq.s IL_001c
IL_0019: ldloc.0 // hello
IL_001a: br.s IL_0023
IL_001c: ldloc.0 // hello
IL_001d: ldc.i4.1
IL_001e: callvirt instance string [mscorlib]System.String::Substring(int32)
IL_0023: stloc.0 // hello
As you can see, the ldloc.0
is exectued in case the :
branch of the logical statement is run (IL_0019
). Right after that the code jumps to IL_0023
which executes the stloc.0
.
This could be an issue with value types, but string
is a reference type and such assignment does not affect the memory at all. To prove it, I have created a big string and run a few value = value
assignments. The heap size never changed.
string hello = new string('a', 3202340);
hello = hello;
hello = hello;
Upvotes: 0
Reputation: 4744
Probably best way to do this is via a regex
using System.Text.RegularExpressions;
...
private static Regex leadingTrailingAsterisks = new Regex("(^\\*)|(\\*$)");
private static string RemoveAllowedAsterisks(string pattern)
{
return leadingTrailingAsterisks.Replace(pattern, "");
}
Upvotes: 0
Reputation: 37020
If you will allow trimming ALL *
characters from the beginning and end of the string (like "**some string**"
), then you can just do:
private string RemoveAllowedAstrisks(string pattern)
{
return pattern?.Trim('*');
}
Upvotes: 1
Reputation: 67195
I prefer the first way because it is more simple and makes it easier for the compiler to make any optimizations.
To be truthful, I don't know if the compiler will optimize away pattern = pattern
in the second approach. It might. Only speed tests will help you determine that.
Personally, I find the second approach more terse but not more readable. And I wouldn't write code that assigns a variable to itself if I didn't need to do that.
A more readable way would be to use string.Trim()
, but I would consider that less efficient.
Upvotes: 0