web-dev-qa-db-ja.com

C#での部分文字列の予期しない動作

.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()を実行しようとすると、例外がスローされるべきではありませんか?

26
Arghya C

documentation は、これが正しい動作であることを明確に示しています。

戻り値:このインスタンスのstartIndexで始まる部分文字列と同等の文字列、またはstartIndexがこのインスタンスの長さと等しい場合は空。

ArgumentOutOfRangeExceptionがゼロ未満または*このインスタンスの長さより大きい場合、startIndexをスローします。 *

つまり、最後の文字のすぐ先から始まる部分文字列を取得すると、空の文字列が得られます。

文字列のpartを与えると期待したコメントは、これと互換性がありません。 「文字列の一部」には、長さがゼロのすべての部分文字列のセットも含まれます。これは、s.substring(n, 0)また空の文字列を生成するという事実からも明らかです。 。

51
paxdiablo

ここには、フレームワークがメソッド呼び出しをどのように処理するかについての技術的な回答がたくさんありますが、なぜのように類推して推論したいと思います。

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)のようなものが_""_も返す理由です。

23
Phylogenesis

コードを見ると便利な場合があります

最初にこれは呼ばれます:

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);
}
13
Royi Namir

MSDNに書かれている内容に基づく:

*

戻り値-このインスタンスのstartIndexで始まる部分文字列と同等の文字列、またはstartIndexがこのインスタンスの長さと等しい場合はEmpty。

ExceptionsArgumentOutOfRangeException --startIndexがゼロ未満、またはこのインスタンスの長さより大きい

*

4
Vasil Indzhev

String.Substring Method のドキュメントを見ると、開始インデックスが長さに等しい場合、空の文字列が返されます。

このインスタンスのstartIndexで始まる長さlengthのサブストリングと同等の文字列、またはstartIndexがこのインスタンスの長さと等しく、長さがゼロの場合はEmpty。

4
Stuart

Substringが行うことは、startIndexが文字列の長さより大きいかどうかをチェックし、その場合にのみ例外をスローすることです。あなたの場合、それは等しいです(文字列の長さは3です)。その後、部分文字列の長さがゼロであるかどうかをチェックし、ゼロであるかどうかはString.Emptyを返します。あなたの場合、部分文字列の長さは、文字列の長さ(3)からstartIndex(3)を引いたものです。これが、部分文字列の長さが0で、空の文字列が返される理由です。

2
DimitarD

他の回答を補足するために、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を返します。

1
Furkan Omay

最後にC#のすべての文字列にはString.Emptyがあります。

ここに良い答えがあります この質問について。

MSDNから- String クラス(システム):

.NET Frameworkでは、Stringオブジェクトにnull文字を埋め込むことができます。これは、文字列の長さの一部としてカウントされます。ただし、CやC++などの一部の言語では、ヌル文字は文字列の終わりを示します。文字列の一部とは見なされず、文字列の長さの一部としてカウントされません。

1
teo van kot