.net _System.String
_クラスのSubstring()
メソッドの定義は次のようになります。
_public string Substring(int startIndex)
_
ここで、startIndex
は"このインスタンスの部分文字列のゼロベースの開始文字位置"メソッド定義に従います。私がそれを正しく理解していれば、それは与えられたゼロベースのインデックスから始まる文字列の一部を私に与えることを意味します。
ここで、文字列_"ABC"
_があり、異なるインデックスを持つ部分文字列を取得すると、次の結果が得られます。
_var str = "ABC";
var chars = str.ToArray(); //returns 3 char 'A', 'B', 'C' as expected
var sub2 = str.Substring(2); //[1] returns "C" as expected
var sub3 = str.Substring(3); //[2] returns "" ...!!! Why no exception??
var sub4 = str.Substring(4); //[3] throws ArgumentOutOfRangeException as expected
_
ケース[2]の例外をスローしないのはなぜですか?
文字列は3文字なので、インデックスは_[0, 1, 2]
_であり、ToArray()
、ToCharArray()
メソッドでも期待どおりに3文字を返します。開始インデックス_3
_でSubstring()
を実行しようとすると、例外がスローされるべきではありませんか?
documentation は、これが正しい動作であることを明確に示しています。
戻り値:このインスタンスのstartIndexで始まる部分文字列と同等の文字列、またはstartIndexがこのインスタンスの長さと等しい場合は空。
ArgumentOutOfRangeException
がゼロ未満または*このインスタンスの長さより大きい場合、startIndex
をスローします。 *
つまり、最後の文字のすぐ先から始まる部分文字列を取得すると、空の文字列が得られます。
文字列のpartを与えると期待したコメントは、これと互換性がありません。 「文字列の一部」には、長さがゼロのすべての部分文字列のセットも含まれます。これは、s.substring(n, 0)
がまた空の文字列を生成するという事実からも明らかです。 。
ここには、フレームワークがメソッド呼び出しをどのように処理するかについての技術的な回答がたくさんありますが、なぜのように類推して推論したいと思います。
string
を、フェンスパネル自体がキャラクターであり、以下に示すように番号が付けられたフェンスの支柱で支えられているフェンスと見なします。
_0 1 2 3
| A | B | C | "ABC"
0 1 2 3 4 5 6 7 8 9
| M | y | | S | t | r | i | n | g | "My String"
_
この例えでは、string.Substring(n)
はfencepoststring
で始まるパネルのn
を返します。文字列の最後の文字の後にフェンスポストがあることに注意してください。このフェンスポストを使用して関数を呼び出すと、このポイントの後にフェンスパネルがないことを示す値が返されます(つまり、空のstring
が返されます)。
同様に、string.Substring(n, l)
は、fencepost string
で始まるl
パネルのn
を返します。これが、"ABC".Substring(2, 0)
のようなものが_""
_も返す理由です。
最初にこれは呼ばれます:
public string Substring(int startIndex)
{
return this.Substring(startIndex, this.Length - startIndex);
}
値の減算により、長さは0です。
public string Substring(int startIndex, int length)
{
if (startIndex < 0)
{
throw new ...
}
if (startIndex > this.Length)
{
throw new ...
}
if (length < 0)
{
throw new ...
}
if (startIndex > (this.Length - length))
{
throw new ...
}
if (length == 0) // <-- NOTICE HERE
{
return Empty;
}
if ((startIndex == 0) && (length == this.Length))
{
return this;
}
return this.InternalSubString(startIndex, length);
}
MSDNに書かれている内容に基づく:
*
戻り値-このインスタンスのstartIndexで始まる部分文字列と同等の文字列、またはstartIndexがこのインスタンスの長さと等しい場合はEmpty。
ExceptionsArgumentOutOfRangeException --startIndexがゼロ未満、またはこのインスタンスの長さより大きい
*
String.Substring Method のドキュメントを見ると、開始インデックスが長さに等しい場合、空の文字列が返されます。
このインスタンスのstartIndexで始まる長さlengthのサブストリングと同等の文字列、またはstartIndexがこのインスタンスの長さと等しく、長さがゼロの場合はEmpty。
Substringが行うことは、startIndexが文字列の長さより大きいかどうかをチェックし、その場合にのみ例外をスローすることです。あなたの場合、それは等しいです(文字列の長さは3です)。その後、部分文字列の長さがゼロであるかどうかをチェックし、ゼロであるかどうかはString.Emptyを返します。あなたの場合、部分文字列の長さは、文字列の長さ(3)からstartIndex(3)を引いたものです。これが、部分文字列の長さが0で、空の文字列が返される理由です。
他の回答を補足するために、Monoもこの動作を正しく実装しています。
public String Substring (int startIndex)
{
if (startIndex == 0)
return this;
if (startIndex < 0 || startIndex > this.length)
throw new ArgumentOutOfRangeException ("startIndex");
return SubstringUnchecked (startIndex, this.length - startIndex);
}
// This method is used by StringBuilder.ToString() and is expected to
// always create a new string object (or return String.Empty).
internal unsafe String SubstringUnchecked (int startIndex, int length)
{
if (length == 0)
return String.Empty;
string tmp = InternalAllocateStr (length);
fixed (char* dest = tmp, src = this) {
CharCopy (dest, src + startIndex, length);
}
return tmp;
}
ご覧のとおり、長さがゼロに等しい場合はString.Emptyを返します。
最後にC#のすべての文字列にはString.Empty
があります。
ここに良い答えがあります この質問について。
MSDNから- String
クラス(システム):
.NET Frameworkでは、Stringオブジェクトにnull文字を埋め込むことができます。これは、文字列の長さの一部としてカウントされます。ただし、CやC++などの一部の言語では、ヌル文字は文字列の終わりを示します。文字列の一部とは見なされず、文字列の長さの一部としてカウントされません。