ทำไมไม่มี Char.Empty เหมือน String.Empty?


259

มีเหตุผลสำหรับสิ่งนี้หรือไม่? ฉันกำลังถามเพราะถ้าคุณจำเป็นต้องใช้ตัวอักษรว่างเปล่าจำนวนมากคุณจะเข้าสู่สถานการณ์เดียวกับที่คุณทำเมื่อคุณใช้สตริงเปล่าจำนวนมาก

แก้ไข: เหตุผลของการใช้งานนี้คือ:

myString.Replace ('c', '')

ดังนั้นลบอินสแตนซ์ทั้งหมดของ 'c's ออกจาก myString


1
ใช่ฉันใช้คำนั้นเพราะขาดคำที่ดีกว่า เช่นวิธีที่แนะนำให้ใช้ String.Empty แทนที่จะเป็น ""
Joan Venge

3
หากคุณกำลังกังวลเกี่ยวกับการตั้งใจ mistyping '' บางครั้งทำไมไม่เพียงแค่ตัดการทำงานในวิธีขยายตามสายของRemoveAll(this string s, params char[] toRemove)? ความตั้งใจจะสื่อสารอย่างชัดเจนและคุณจะไม่เสี่ยงต่อการพิมพ์ผิดอะไร
bzlm

12
@Henk - เหตุผลเดียวที่ฉันใช้ string.Empty ก็คือเพราะฉันพบวัตถุว่างเปล่าที่จัดทำโดย Empty แสดงเจตนาที่ดีกว่าราคาที่ว่างเปล่า คำพูดที่ว่างเปล่าอาจเป็นผลมาจากปัญหาการรวมหรือความคิดที่ผิดพลาดหรืออาจเป็นเจตนาที่แท้จริงของรหัสนั้นในขณะที่ Empty บอกฉันอย่างชัดเจนว่าผู้พัฒนาตั้งใจให้สตริงนั้นไม่มีข้อมูล
Ritch Melton

3
มีความแตกต่างระหว่าง "" และสตริง ไม่ใช่ทุกคนที่สนใจจริงๆ แต่ "" สร้างวัตถุในขณะที่สตริงส่วนที่เหลือจะใช้สิ่งที่สร้างไว้แล้ว แต่อีกครั้งมันมีขนาดเล็กเพียงว่าสถานการณ์พิเศษเท่านั้นที่จะทำให้ความแตกต่าง
marcelo-ferraz

1
@ marcelo-ferrazm เกี่ยวกับการ""สร้างวัตถุ : ไม่มันไม่ได้
Henk Holterman

คำตอบ:


272

ไม่มีสิ่งนั้นเป็นตัวละครที่ว่างเปล่า สิ่งที่ใกล้เคียงที่สุดที่คุณจะได้รับคือ'\0'อักขระ Unicode "null" เนื่องจากคุณสามารถฝังไว้ภายในตัวอักษรสตริงหรือแสดงมันด้วยตัวเองได้อย่างง่ายดายทำไมคุณต้องการเขตข้อมูลแยกต่างหาก ข้อโต้แย้ง"มันง่ายที่จะทำให้สับสน""และ" "" ไม่ได้ใช้'\0'กัน

หากคุณสามารถยกตัวอย่างว่าคุณต้องการใช้ที่ใดและทำไมคุณคิดว่ามันจะดีกว่านั่นอาจช่วย ...


2
\ 0 ไม่ได้เป็น 'จุดสิ้นสุดของอักขระอาร์เรย์' หรือไม่ หรือฉันสับสนกับสิ่งอื่นหรือไม่
Bertvan

5
@Bertvan: ทำไมจะมีตัวละครในตอนท้ายของอาร์เรย์ไบต์ ? มันใช้สำหรับสตริง "null terminated" ใช่
Jon Skeet

35
Char.MinValue ดีกว่า '\ 0'
Aliostad

10
@Aliostad: หากคุณมีเขตข้อมูลที่คล้ายกันInt32.Zeroคุณจะใช้มันแทนตัวอักษร 0 หรือไม่ ถ้าไม่ต่างกันตรงไหน?
Jon Skeet

7
@Adam, @Jon - รหัสสำหรับระฆังคืออะไร? หรือแบ็คสเปซดีกว่าคิดว่า ... หรือบางทีแทนที่จะคิดว่ามันเป็นการดีกว่าที่จะเขียน Char.Backspace? อีกเหตุผลหนึ่ง - คุณบอกว่าเป็นการดีกว่าที่จะเขียน '0' สำหรับ terminator แทนพูดว่า Char.Terminator แต่ไม่ใช่ - ง่ายเกินไปที่จะพิมพ์ผิด (เรียบเรียงอย่างเต็มที่ดูด้านบน) แต่พยายามเขียน Char.Termnator มีเหตุผลมากพอสำหรับฉันที่จะหลีกเลี่ยงค่าที่ไม่สามารถตรวจสอบได้, วัตถุดิบ (ภารกิจอวกาศล้มเหลวเนื่องจากความผิดพลาดแบบนั้น)
greenoldman

87

ถ่านซึ่งแตกต่างจากสตริงเป็นสิ่งที่ไม่ต่อเนื่องที่มีขนาดคงที่ สตริงเป็นที่บรรจุตัวอักษรจริงๆ

ดังนั้น Char.Empty ไม่เข้าใจในบริบทนั้นจริงๆ หากคุณมีถ่านมันไม่ว่างเปล่า


3
ถูกต้อง มันสมเหตุสมผลที่จะถามว่าคอนเทนเนอร์ว่างเปล่าหรือไม่ มันไม่มีเหตุผลที่จะถามถึง int หรือ float หรือ char ว่างเปล่า
TED

1
@ โจ: แล้วสตริงจะว่างได้อย่างไรถ้าสตริงเป็นชุดของตัวอักษร (ไม่ว่าง)? อาจโง่ขออภัย ...
1477388

9
เนื่องจากสตริงไม่ใช่วัตถุเดี่ยวจึงเป็นชุดสะสม ลองนึกถึงถังหิน ฉันไม่มีหินที่ว่างเปล่า แต่ฉันสามารถมีถังที่ว่างเปล่า
Joe

2
ฉันจะวลีมันว่า "ถ่านเป็นดึกดำบรรพ์ชนิดของค่าและสตริงเป็นไม่ดึกดำบรรพ์ประเภทอ้างอิง"
samis

3
นี่คือคำตอบที่แท้จริง
Gandalf458

31

ไม่มีสิ่งใดเป็นตัวละครที่ว่างเปล่า มันมีบางสิ่งบางอย่างเสมอ แม้แต่ '\ 0' ก็คือตัวละคร


28

ใช้Char.MinValueสิ่งที่ทำงานเหมือนกับ '\ 0' String.Emptyแต่ต้องระวังมันไม่ได้เป็นเช่นเดียวกับ


ขอบคุณไม่เคยเห็นแบบนั้นมาก่อน คุณรู้หรือไม่ถ้ามันทำงานใน myString.Replace ('c', Char.MinValue)? ฉันควรจะลองดู
Joan Venge

19

คุณสามารถใช้nullableตัวอักษร

char? c

สิ่งนี้อนุญาตให้ '' หรือเป็นโมฆะ?
Joan Venge

ในกรณีของคุณคุณสามารถทำสิ่งนี้: myString.Replace ("c", (c == null? "": c.ToString ()))
paquetp

12

หากคุณไม่ต้องการสตริงทั้งหมดคุณสามารถใช้ประโยชน์จากการดำเนินการล่าช้า:

public static class StringExtensions
{
    public static IEnumerable<char> RemoveChar(this IEnumerable<char> originalString, char removingChar)
    {
        return originalString.Where(@char => @char != removingChar);
    }
}

คุณสามารถรวมอักขระหลายตัว ...

string veryLongText = "abcdefghijk...";

IEnumerable<char> firstFiveCharsWithoutCsAndDs = veryLongText
            .RemoveChar('c')
            .RemoveChar('d')
            .Take(5);

... และจะมีการประเมินเฉพาะอักขระ 7 ตัวแรกเท่านั้น :)

แก้ไข: หรือดียิ่งขึ้น:

public static class StringExtensions
{
    public static IEnumerable<char> RemoveChars(this IEnumerable<char> originalString,
        params char[] removingChars)
    {
        return originalString.Except(removingChars);
    }
}

และการใช้งาน:

        var veryLongText = "abcdefghijk...";
        IEnumerable<char> firstFiveCharsWithoutCsAndDs = veryLongText
            .RemoveChars('c', 'd')
            .Take(5)
            .ToArray(); //to prevent multiple execution of "RemoveChars"

@ จุน: ขอบคุณ ... แม้ว่า "Genius" มันพูดเกินจริงไปหน่อย: P (ฉันไม่รู้เกี่ยวกับการแสดงเมื่อลบชาจะกลายเป็นอาร์เรย์ใหญ่ ... )
Notoriousxl

1
เมื่อวานฉันลืม: โปรดใส่ใจกับวิธีที่คุณใช้ตัวแปรผลลัพธ์ "firstFiveCharsWithoutCsAndDs" หากคุณไม่ต้องการส่งผ่านไปยังวิธีการ "ให้ผลผลิต" อื่น (เช่นเดียวกับ LINQ) ให้โทรหา ".ToArray ()" ทันทีหลังจาก "ใช้ (5)" ... มิฉะนั้น "RemoveChars + Take" ลูกโซ่จะถูกดำเนินการทุกครั้งที่คุณเข้าถึงตัวแปรในแบบ "ดั้งเดิม" (ตัวอย่างเช่นทุกครั้งที่คุณเรียกว่า "Count ()" บนมันหรือเมื่อคุณเข้าไปในตัวแปรโดยไม่ต้อง "ส่งคืนผลตอบแทน"
Notoriousxl

+1 มีความคิดดี แต่ไม่สามารถได้รับการบำรุงรักษาอย่างมีประสิทธิภาพหรือเป็นวิธีการขั้นพื้นฐาน :)
Nawfal

1
@nawfal ประสิทธิภาพ - ฉลาดคุณพูดถูก แต่ฉันคิดว่า myString.Except ("c") มีความชัดเจนมากกว่า myString.Replace ('c', ''): P (และมันก็ค่อนข้างดี: myString.Except ( "aeiou"))
Notoriousxl

7
myString = myString.Replace('c'.ToString(), "");

ตกลงนี้ไม่ได้สวยงามโดยเฉพาะอย่างยิ่งสำหรับการลบตัวอักษรเนื่องจากวิธีการแทนที่มีโอเวอร์โหลดที่ใช้พารามิเตอร์สตริง แต่ใช้งานได้สำหรับการลบการขึ้นบรรทัดใหม่ฟีดบรรทัดแท็บ ฯลฯ ตัวอย่างนี้จะลบอักขระแท็บ:

myString = myString.Replace('\t'.ToString(), "");

6

int.Emptyด้วยเหตุผลเดียวกันที่มีอยู่ไม่ ภาชนะบรรจุอาจว่างเปล่า ค่าสเกลาร์ไม่สามารถเป็นได้ ถ้าคุณหมายถึง 0 (ซึ่งไม่ว่างเปล่า) '\0'แล้วใช้ ถ้าคุณหมายถึงnullใช้null:)


2
ไม่สามารถใช้ null ได้เนื่องจาก char เป็น ValueType คุณจะต้องใช้ถ่าน? เพื่อให้สามารถกำหนดค่า null ให้กับมัน
Femaref

คุณควรทำให้เป็นโมฆะ ดูคำตอบของฉัน
paquetp

5

ถ่านเป็นประเภทค่าดังนั้นค่าของมันจึงไม่สามารถเป็นค่าว่างได้ (เว้นเสียแต่ว่ามันจะถูกห่อไว้ในภาชนะที่ว่างเปล่า)

เนื่องจากมันไม่สามารถเป็นโมฆะในมีรหัสตัวเลขบางรหัสและแต่ละรหัสจะถูกแมปกับตัวละครบางตัว


4

ไม่ใช่คำตอบสำหรับคำถามของคุณ แต่เพื่อแสดงถึงค่าเริ่มต้นที่charคุณสามารถใช้ได้

default(char)

ซึ่งเป็นเช่นเดียวซึ่งจะเป็นเช่นเดียวกับchar.MinValue \0หนึ่งไม่ควรใช้ถ้าสำหรับสิ่งที่ต้องการสตริงว่างแม้ว่า


1

ไม่ตอบคำถามแรกของคุณ - แต่สำหรับปัญหาเฉพาะที่คุณมีคุณสามารถใช้สายอักขระแทนตัวอักษรใช่ไหม:

myString.Replace("c", "")

มีเหตุผลที่คุณไม่ต้องการทำเช่นนั้น?


1

นอกจากนี้คุณยังสามารถสร้างอักขระสตริงของคุณใหม่ตามตัวอักษรโดยไม่รวมอักขระที่คุณต้องการกำจัด

ต่อไปนี้เป็นวิธีส่วนขยายในการทำเช่นนี้

    static public string RemoveAny(this string s, string charsToRemove)
    {
        var result = "";
        foreach (var c in s)
            if (charsToRemove.Contains(c))
                continue;
            else
                result += c;

        return result;
    }

มันไม่ลื่นหรือแฟนซี แต่มันใช้งานได้ดี

ใช้แบบนี้:

string newString = "My_String".RemoveAny("_"); //yields "MyString"

ใช้สำหรับStringBuilder resultทำไมไม่ห่อreturn s.Replace(charsToRemove,"");?
aloisdg กำลังย้ายไปยัง codidact.com

1

หากคุณต้องการลบอักขระที่ตรงตามเงื่อนไขคุณสามารถใช้สิ่งนี้:

string s = "SoMEthInG";
s = new string(s.Where(c => char.IsUpper(c)).ToArray());

(การดำเนินการนี้จะทำให้มีเพียงอักขระตัวพิมพ์ใหญ่ในสตริง)

กล่าวอีกนัยหนึ่งคุณอาจ "ใช้" สตริงเป็นIEnumerable<char>ทำการเปลี่ยนแปลงและเปลี่ยนกลับเป็นสตริงตามที่แสดงด้านบน

อีกครั้งนี้ช่วยให้ไม่เพียง c => c != 't'แต่เอาถ่านที่เฉพาะเจาะจงเพราะการแสดงออกแลมบ์ดาแม้ว่าคุณสามารถทำได้ถ้าคุณเปลี่ยนการแสดงออกแลมบ์ดาเช่นนี้:


0

อักขระเกี่ยวกับBOMคืออะไร Microsoft เพิ่มการเริ่มต้นของไฟล์ (อย่างน้อย XML)


ถ้อยคำในวิกิพีเดียที่นี่ค่อนข้างโชคร้าย BOM ไม่ใช่ตัวละครในบริบทนี้ และคำถามของคุณคืออะไร? :)
bzlm

@onemach ดังนั้นไม่ว่าจะประสบความสำเร็จโดยmyString.Replace ('c', '') myString.Replace ('c', UTF_BOM)ถ้าอย่างนั้นฉันจะบอกว่าคำตอบคือ " ไม่เกี่ยวกับ ... "
bzlm

0

หากคุณต้องการกำจัดถ่านที่ว่างเปล่าในสตริงต่อไปนี้จะใช้งานได้เพียงแค่แปลงเป็นประเภทข้อมูลที่คุณต้องการ ขอบคุณ

private void button1_Click(object sender, EventArgs e)
    {

        Int32 i;

        String name;

        Int32[] array_number = new int[100];

        name = "1 3  5  17   8    9    6";

        name = name.Replace(' ', 'x');

        char[] chr = name.ToCharArray();


        for (i = 0; i < name.Length; i++)
        {
            if ((chr[i] != 'x'))
            {
                array_number[i] = Convert.ToInt32(chr[i].ToString());
                MessageBox.Show(array_number[i].ToString());
            }

        }

    }

0

ในแง่ของภาษา C # สิ่งต่อไปนี้อาจไม่สมเหตุสมผลนัก และนี่ไม่ใช่คำตอบสำหรับคำถามโดยตรง แต่ fowlloing คือสิ่งที่ฉันทำในสถานการณ์ธุรกิจ

        char? myCharFromUI = Convert.ToChar(" ");
        string myStringForDatabaseInsert = myCharFromUI.ToString().Trim();
        if (String.IsNullOrEmpty(myStringForDatabaseInsert.Trim()))
        {
            Console.Write("Success");
        }

nullและwhite spaceธุรกิจที่แตกต่างมีกระแสในโครงการของฉัน ในขณะที่ใส่เข้าไปในฐานข้อมูลฉันต้องแทรกempty stringลงในฐานข้อมูลถ้ามันเป็นพื้นที่สีขาว


0

ฉันรู้ว่าอันนี้ค่อนข้างเก่า แต่ฉันพบปัญหาเมื่อเร็ว ๆ นี้โดยต้องทำการแทนที่หลายรายการเพื่อทำให้ชื่อไฟล์ปลอดภัย ครั้งแรกในสตริง. NET ล่าสุดฟังก์ชั่นแทนที่เป็นโมฆะเทียบเท่ากับตัวละครที่ว่างเปล่า ต้องบอกว่าสิ่งที่ขาดหายไปจาก. Net เป็นเรื่องง่ายที่จะแทนที่ทุกสิ่งที่จะแทนที่ตัวละครในอาร์เรย์ด้วยตัวละครที่ต้องการ โปรดอ้างอิงรหัสด้านล่าง (ทำงานใน LinqPad เพื่อทำการทดสอบ)

// LinqPad .ReplaceAll and SafeFileName
void Main()
{

    ("a:B:C").Replace(":", "_").Dump();                     // can only replace 1 character for one character => a_B_C
    ("a:B:C").Replace(":", null).Dump();                    // null replaces with empty => aBC
    ("a:B*C").Replace(":", null).Replace("*",null).Dump();  // Have to chain for multiples 

    // Need a ReplaceAll, so I don't have to chain calls


    ("abc/123.txt").SafeFileName().Dump();
    ("abc/1/2/3.txt").SafeFileName().Dump();
    ("a:bc/1/2/3.txt").SafeFileName().Dump();
    ("a:bc/1/2/3.txt").SafeFileName('_').Dump();
    //("abc/123").SafeFileName(':').Dump(); // Throws exception as expected

}


static class StringExtensions
{

    public static string SafeFileName(this string value, char? replacement = null)
    {
        return value.ReplaceAll(replacement, ':','*','?','"','<','>', '|', '/', '\\');
    }

    public static string ReplaceAll(this string value, char? replacement, params char[] charsToGo){

        if(replacement.HasValue == false){
                return string.Join("", value.AsEnumerable().Where(x => charsToGo.Contains(x) == false));
        }
        else{

            if(charsToGo.Contains(replacement.Value)){
                throw new ArgumentException(string.Format("Replacement '{0}' is invalid.  ", replacement), "replacement");
            }

            return string.Join("", value.AsEnumerable().Select(x => charsToGo.Contains(x) == true ? replacement : x));
        }

    }

}


-3

วิธีที่ง่ายที่สุดในการครอบคลุมลบอักขระจากสตริงคือการตัดมัน

cl = cl.Trim(' ');

ลบช่องว่างทั้งหมดในสตริง


สิ่งนี้มีประโยชน์หากต้องการใช้. แทนที่ ('c', '') พร้อมกับข้อเสียของการลบช่องว่างอื่น ๆ แต่มันมีประโยชน์มากกว่าคำตอบอื่น ๆ อีกมากมาย
Jan

1
ไม่ผิด! ตัดแต่งเพียงลบตัวอักษรออกจากจุดเริ่มต้นและจุดสิ้นสุดของสตริงที่ไม่ได้อยู่ตรงกลาง
userSteve
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.