Why does "abcd".StartsWith("") return true? - c#

Title is the entire question. Can someone give me a reason why this happens?

Yes - because it does begin with the empty string. Indeed, the empty string logically occurs between every pair of characters.
Put it this way: what definition of "starts with" could you give that would preclude this? Here's a simple definition of "starts with" that doesn't:
"x starts with y if the first y.Length characters of x match those of y."
An alternative (equivalent) definition:
"x starts with y if x.Substring(0, y.Length).Equals(y)"

I will try to elaborate on what Jon Skeet said.
Let's say x, y and z are strings and + operator is in fact concatenation, then:
If we can split z to write z = x + y that means that z starts with x.
Because every string z can be split to z = "" + z it follows that every string starts with "".
So, because ("" + "abcd") == "abcd" it follows that "abcd" starts with ""

I'll start with a related fact that is easier to understand.
The empty set is a subset of every set.
Why? The definition of subset states that A is a subset of B if every element of A is an element of B. Conversely, A is not a subset of B if there is an element of A that is not an element of B.
Now fix a set B. I'll establish that the empty set is a subset of B. I'll do this by showing that it is not the case that the empty set is not a subset of B. If the empty set were not a subset of B then I could find an element of the empty set that is not in B. But the empty set does not have any elements and thus I can not find an element that is not in B. Therefore, it is not the case that the empty set is not a subset of B. Thus, the empty set must be a subset of B.
Any string starts with the empty string.
First, we must agree on our definition of starts with. Let s and t be strings We say that s starts with t if s.Length >= t.Length and the first t.Length characters of t match those of s. That is, s.Length >= t.Length and for every Int32 index such that 0 <= index < t.Length, s[index] == t[index] is true. Conversely, we would say that s does not start with t if the statement
s.Length < t.Length or s.Length >= t.Length and there is an Int32 index such that 0 <= index < t.Length and s[index] != t[index]
is true. In plain English, s is shorter than t, or, if not, there is a character in t not matching the character as the same position in s.
Now fix a string s. I'll establish that s starts with the empty string. I'll do this by showing that it is not the case that s does not start with the empty string. If s does not start with the empty string then s.Length < String.Empty.Length or s.Length >= String.Empty.Length and there is an Int32 index such that 0 <= index < String.Empty.Length. But s.Length >= 0 and String.Empty.Length is equal to zero so it is impossible for s.Length < String.Empty.Length to be true. Similarly, since ``String.Empty.Lengthis equal to zero, there is noInt32 indexsatisfying0 <= index < String.Empty.Length`. Therefore
s.Length < String.Empty.Length or s.Length >= String.Empty.Length and there is an Int32 index such that 0 <= index < String.Empty.Length
is false. Therefore, it is not the case that s does not start with the empty string. Thus, s must start with the empty string.
The following is an implementation of starts with coded as an extension to string.
public static bool DoStartsWith(this string s, string t) {
if (s.Length >= t.Length) {
for (int index = 0; index < t.Length; index++) {
if (s[index] != t[index]) {
return false;
}
}
return true;
}
return false;
}
The above two bolded facts are examples of vacuously true statements. They are true by virtue of the fact that the statements defining them (subset and starts with) are universal quantifications over empty universes. There are no elements in the empty set, so there can not be any elements of the empty set not in some other fixed set. There are no characters in the empty string, so there can not be a character as some position in the empty string not matching the character in the same position in some other fixed string.

This method compares the value parameter to the substring at the beginning of this string that is the same length as value, and returns a value that indicates whether they are equal. To be equal, value must be an empty string (Empty), a reference to this same instance, or match the beginning of this instance.
.NET String.StartsWith
true if the character sequence represented by the argument is a prefix of the character sequence represented by this string; false otherwise. Note also that true will be returned if the argument is an empty string or is equal to this String object as determined by the equals(Object) method.
Java String.startsWith

Let's just say "abcd".StartsWith("") returns false.
if so then what does the following expression eval to, true or false:
("abcd".Substring(0,0) == "")
it turns out that evals to true, so the string does start with the empty string ;-), or put in other words, the substring of "abcd" starting at position 0 and having 0 length equals the empty string "". Pretty logical imo.

In C# this is how the specification tells it to react;
To be equal, value must be an empty string (Empty), a reference to this same instance, or match the beginning of this instance.

The first N characters of the two strings are identical. N being the length of the second string, i.e. zero.

Why does “abcd”.StartsWith(“”) return true?
THE REAL ANSWER:
It has to be that way otherwise you'd have the case where
"".startsWith("") == false
"".equals("") == true
but yet
"a".startsWith("a") == true
"a".equals("a") == true
and then we'd have Y2K all over again because all the bank software that depends on equal strings starting with themselves will get our accounts mixed up and suddenly Bill Gates will have my wealth and I'd have his, and damn it! Fate just isn't that kind to me.

Just for the record, String.StartsWith() internally calls the method System.Globalization.CultureInfo.IsPrefix() which makes the following check explicitly:
if (prefix.Length == 0)
{
return true;
}

Because a string begins well with "nothing".

If you think of it in regular expressions terms, it makes sense.
Every string (not just "abcd", also "" and "sdf\nff") ,
returns true when evaluating the regular expression of 'starts with empty string'.

Related

Why we use -1 within a for Loop c#

I have code which checks if a word if a palindrome or not. Within the for loop there is a -1 value. Can someone explain to me why -1 is used after the name.Length in c#
public static void Main()
{
string name = "Apple";
string reverse = string.Empty;
for (int i = name.Length - 1; i >= 0; i--)
{
reverse +=name[i];
}
if (name == reverse)
{
Console.WriteLine($"{name} is palindrome");
}else
{
Console.WriteLine($"{name} is not palindrome");
}
That's because whoever wrote the code, wanted to write:
reverse += name[i];
String operator [] takes values from 0 upto (string's length-1). If you pass length or more, you will get an exception. So, code's author had to ensure that i==Length won't be ever passed there. So it starts from Length-1 and counts downwards.
Also, note that the other bound of i is 0 (>=, not >, so 0 is included), so the loop visits all values from 0 to length-1, so it visits all characters from the string. Job done.
However, it doesn't have to be written in that way. The only thing is to ensure that the string operator [] wont see values of of its range. Compare this loop, it's identical in its results:
for (int i = name.Length; i >= 1; i--)
{
reverse += name[i-1];
}
Note that I also changed 0 to 1.
Of course, it's also possible to write a loop with the same effects in a lot of other ways.
The first element in an array is at the index 0 (array[0]). Because the indexing starts at 0 instead of 1 it means that the final element in the array will be at index array.Length-1.
If you had the word and then your array would look like:
name[0] = 'a'
name[1] = 'n'
name[2] = 'd'
the name.Length would equal 3. As you can see, there isn't an element at index 3 in the array so you need to subtract 1 from the length of the array to access the last element.
The for loop in your example starts with the last element in the array (using i as the index). If you tried to set i to i = name.Length then you would get an index out of bounds error because there isn't an element at the position name.Length.
String operator [] takes values from 0. The first element in an string is at the index 0, so we need to adjust by subtracting one.
For Example:
string str = "test";
int length = str.length; //Length of the str is 4. (0 to 3)

OutOfRangeException in StringBuilder.Remove()

I have a string which contains a lot of useless information after the first char: space. So I built a StringBuilder to remove unnecesary characters after the first space.
public static string Remove(string text)
{
int index1 = text.IndexOf(' ');
int index2 = text.Lenght;
StringBuilder sv = new StringBuilder(text.Lenght);
sv.Append(text);
sv.Remove(index1, index2);
string text2 = sv.ToString();
return text2;
}
Can somebody explain why this throws me an error? Thank you!
The reason for this exception is that you misunderstood the purpose of the second parameter: rather than specifying the ending index, it specifies the length of the segment to be removed.
Since your code is passing the length of the entire text string, the only valid input for the first parameter would be zero. To pass a proper value, subtract the first index from the second index, and add 1 to the result.
Note: It looks like you are removing everything from the string starting at the first space ' '. A simpler way of doing it would be with substring:
int index = text.IndexOf(' ');
return index >= 0 ? text.Substring(0, index) : text;
The documentation for Remove says it all - only one exception is raised for that method
ArgumentOutOfRangeException: If startIndex or length is less than zero, or startIndex + length is greater than the length of this instance.
So one of two things is going on
Your string does not contain a space (startIndex will be less than zero)
The startIndex+length is greater than the total length of the string.
Crucially, with the code you've posted 1. above could sometimes be true, and 2. will always be true! You should have done index2-index1 for the second parameter.

How string quote, length total count and arrayname[int] work?

I'm making a program which reverses words to sdrow.
I understand that for it to work it needs to be written this way.
I'm more interested on WHY it has to be this way.
Here is my code:
Console.WriteLine("Enter a word : ");
string word = Console.ReadLine();
string rev = "";
int length;
for (length = word.Length - 1; length >= 0; length--)
{
rev = rev + word[length];
}
Console.WriteLine("The reversed word is : {0}", rev);
My questions are:
a) why you must use quotes to initialize your string
b) Why must you start your loop at one less than the total length of your string
c) How arrayname[int] works
I'm pretty new to C# and this site, as well. I hope my questions make sense and that I've asked them in the correct and proper way.
Thank you for your time!
This is how I've interpreted your question.
You want to know why you must use quotes to initialize your string
Why must you start your loop at one less than the total length of your string
How arrayname[int] works
I think that the best way to explain this to you is to go through your code, and explain what it does.
Console.WriteLine("Enter a word : ");
The first line of code prints Enter a word : into the console.
string word = Console.ReadLine();
This line "reads" the input from the console, and puts it into a string called word.
string rev = "";
This initiates a string called rev, setting it's value to "", or an empty string. The other way to initiate the string would be this:
string rev;
That would initiate a string called rev to the value of null. This does not work for your program because rev = rev + word[length]; sets rev to itself + word[length]. It throws an error if it is null.
The next line of your code is:
int length;
That sets an int (which in real life we call an integer, basically a number) to the value of null. That is okay, because it gets set later on without referencing itself.
The next line is a for loop:
for (length = word.Length - 1; length >= 0; length--)
This loop sets an internal variable called length to the current value of word.Length -1. The second item tells how long to run the loop. While the value of length is more than, or equal to 0, the loop will continue to run. The third item generally sets the rate of increase or decrease of your variable. In this case, it is length-- that decreases length by one each time the loop runs.
The next relevant line of code is his:
rev = rev + word[length];
This, as I said before sets rev as itself + the string word at the index of length, whatever number that is at the time.
At the first run through the for loop, rev is set to itself (an empty string), plus the word at the index of length - 1. If the word entered was come (for example), the index 0 would be c, the index 1 would be o, 2 would be m, and 3 = e.
The word length is 4, so that minus one is 3 (yay - back to Kindergarten), which is the last letter in the word.
The second time through the loop, length will be 2, so rev will be itself (e) plus index 2, which is m. This repeats until length hits -1, at which point the loop does not run, and you go on to the next line of code.
...Which is:
Console.WriteLine("The reversed word is : {0}", rev);
This prints a line to the console, saying The reversed word is : <insert value of rev here> The {0} is an internal var set by the stuff after the comma, which in this case would be rev.
The final output of the program, if you inserted come, would look something like this:
>Enter a word :
>come
>
>The reversed word is : emoc
a) you must to initialize or instantiate the variable in order to can work with it. In your case is better to use and StringBuilder, the string are inmutable objects, so each assignement means to recreate a new string.
b) The arrays in C# are zero index based so their indexes go from zero to length -1.
c) An string is an characters array.
Any case maybe you must to try the StringBuilder, it is pretty easy to use
I hope this helps
a) you need to initialize a variable if you want to use it in an assignment rev = rev + word[length];
b) you are using a for loop which means that you define a start number length = word.Length - 1, a stop criteria length >= 0 and a variable change length--
So lenght basically descends from 5 to 0 (makes 6 loops). The reason is that Arrays like 'string' a char[] are zerobased indexed.. means that first element is 0 last is array.Length - 1
c) So a string is basically a chain of char's.. with the []-Operator you can access a single index. The Return Type of words[index] is in this case a character.
I hope it helped
a) You need to first instantiate the string rev before you can assign it values in the loop. You could also say "string rev = String.Empty". You are trying to add word to rev and if you don't tell it first that rev is an empty string it doesn't know what it is adding word to.
b) The characters of the string have indexes to show which position they appear in the string. These indexes start at 0. So you're first character will have an index of 0. If the length of your string is 6 then the last character's index will be 5. So length - 1 will give you the value of the last character's index which is 5. A c# for loop uses the following parameters
for (int i = 0; i < 10; i++)
{
Console.WriteLine(i);
}
where "int i = 0;" is the starting index; "i < 10" tells the loop when to stop looping; and "i++" tells it to increment i (the index) after each loop.
So in your code you are saying start at the last character of my string; perform this loop while there are still characters in the string; and decrease the index of the string after each loop so the next loop will look at the previous character in the string.
c) word[length] then in this scenario is saying add the character that has the position with index "length" to the rev string. This will basically reverse the word.
As usual you can do it in linq and avoid the (explicit) loops
using System;
using System.Linq;
namespace ConsoleApplication1
{
class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Enter a word : ");
string word = Console.ReadLine();
Console.WriteLine("The reversed word is : {0}", new string (word.Reverse().ToArray()));
Console.ReadLine();
}
}
}
var reversedWords = string.Join(" ",
str.Split(' ')
.Select(x => new String(x.Reverse().ToArray())));
Take a look here :
Easy way to reverse each word in a sentence

Constantly Incrementing String

So, what I'm trying to do this something like this: (example)
a,b,c,d.. etc. aa,ab,ac.. etc. ba,bb,bc, etc.
So, this can essentially be explained as generally increasing and just printing all possible variations, starting at a. So far, I've been able to do it with one letter, starting out like this:
for (int i = 97; i <= 122; i++)
{
item = (char)i
}
But, I'm unable to eventually add the second letter, third letter, and so forth. Is anyone able to provide input? Thanks.
Since there hasn't been a solution so far that would literally "increment a string", here is one that does:
static string Increment(string s) {
if (s.All(c => c == 'z')) {
return new string('a', s.Length + 1);
}
var res = s.ToCharArray();
var pos = res.Length - 1;
do {
if (res[pos] != 'z') {
res[pos]++;
break;
}
res[pos--] = 'a';
} while (true);
return new string(res);
}
The idea is simple: pretend that letters are your digits, and do an increment the way they teach in an elementary school. Start from the rightmost "digit", and increment it. If you hit a nine (which is 'z' in our system), move on to the prior digit; otherwise, you are done incrementing.
The obvious special case is when the "number" is composed entirely of nines. This is when your "counter" needs to roll to the next size up, and add a "digit". This special condition is checked at the beginning of the method: if the string is composed of N letters 'z', a string of N+1 letter 'a's is returned.
Here is a link to a quick demonstration of this code on ideone.
Each iteration of Your for loop is completely
overwriting what is in "item" - the for loop is just assigning one character "i" at a time
If item is a String, Use something like this:
item = "";
for (int i = 97; i <= 122; i++)
{
item += (char)i;
}
something to the affect of
public string IncrementString(string value)
{
if (string.IsNullOrEmpty(value)) return "a";
var chars = value.ToArray();
var last = chars.Last();
if(char.ToByte() == 122)
return value + "a";
return value.SubString(0, value.Length) + (char)(char.ToByte()+1);
}
you'll probably need to convert the char to a byte. That can be encapsulated in an extension method like static int ToByte(this char);
StringBuilder is a better choice when building large amounts of strings. so you may want to consider using that instead of string concatenation.
Another way to look at this is that you want to count in base 26. The computer is very good at counting and since it always has to convert from base 2 (binary), which is the way it stores values, to base 10 (decimal--the number system you and I generally think in), converting to different number bases is also very easy.
There's a general base converter here https://stackoverflow.com/a/3265796/351385 which converts an array of bytes to an arbitrary base. Once you have a good understanding of number bases and can understand that code, it's a simple matter to create a base 26 counter that counts in binary, but converts to base 26 for display.

Neat solution to a counting within a string

I am trying to solve the following problem but cannot find an elegant solution. Any ideas?
Thanks.
Input - a variable length string of numbers, e.g.,
string str = "5557476374202110373551116201";
Task - Check (from left to right) that each number (ignoring the repetitions) does not appear in the following 2 indexes. Using eg. above, First number = 5. Ignoring reps we see that last index of 5 in the group is 2. So we check next 2 indexes, i.e. 3 and 4 should not have 5. If it does we count it as error. Goal is to count such errors in the string.
In the above string errors are at indexes, 3,10 and 16.
in addition to the other excellent solutions you can use a simple regexp:
foreach (Match m in Regexp.Matches(str, #"(\d)(?!\1)(?=\d\1)"))
Console.WriteLine("Error: " + m.Index);
returns 3,10,16. this would match adjacent errors using lookahead with a backreference. handles repetitions. .net should support that. if not, you can use a non-backreference version:
(?<=0[^0])0|(?<=1[^1])1|(?<=2[^2])2|(?<=3[^3])3|(?<=4[^4])4|(?<=5[^5])5|(?<=6[^6])6|(?<=7[^7])7|(?<=8[^8])8|(?<=9[^9])9
A simple indexed for loop with a couple of look ahead if checks would work. You can treat a string as a char[] or as an IEnumerable - either way you can use that to loop over all of the characters and perform a lookahead check to see if the following one or two characters is a duplicate.
Sorry, not a C# man, but here's a simple solution in Ruby:
a="5557476374202110373551116201"
0.upto(a.length) do |i|
puts "error at #{i}" if a[i]!=a[i+1] && a[i]==a[i+2]
end
Output:
error at 3
error at 10
error at 16
Here's something I threw together in C# that worked with the example input from the question. I haven't checked it that thoroughly, though...
public static IEnumerable<int> GetErrorIndices(string text) {
if (string.IsNullOrEmpty(text))
yield break;
int i = 0;
while (i < text.Length) {
char c = text[i];
// get the index of the next character that isn't a repetition
int nextIndex = i + 1;
while (nextIndex < text.Length && text[nextIndex] == c)
nextIndex++;
// if we've reached the end of the string, there's no error
if (nextIndex + 1 >= text.Length)
break;
// we actually only care about text[nextIndex + 1],
// NOT text[nextIndex] ... why? because text[nextIndex]
// CAN'T be a repetition (we already skipped to the first
// non-repetition)
if (text[nextIndex + 1] == c)
yield return i;
i = nextIndex;
}
yield break;
}

Categories