Dlaczego nie ma Char.Empty jak String.Empty?

259

Czy jest tego powód? Pytam, ponieważ jeśli musisz użyć wielu pustych znaków, to znajdziesz się w takiej samej sytuacji, jak wtedy, gdy używasz wielu pustych łańcuchów.

Edycja: Powodem tego użycia było:

myString.Replace ('c', '')

Więc usuń wszystkie wystąpienia 'c's z myString.

Joan Venge
źródło
1
Tak, użyłem tego słowa z powodu braku lepszego słowa. tj. zalecany sposób użycia String.Empty zamiast „”.
Joan Venge
3
Jeśli czasami martwi Cię przypadkowe błędne wpisanie '', dlaczego nie po prostu zawinąć funkcjonalność w metodę rozszerzenia wzdłuż linii RemoveAll(this string s, params char[] toRemove)? Cel zostanie wyraźnie przekazany i nie ryzykujesz błędnego wpisania.
bzlm
12
@Henk - Jedynym powodem, dla którego używam string.Empty jest to, że znajduję pusty obiekt podany przez Empty wyraża zamiar lepiej niż puste cudzysłowy. Puste cytaty mogą wynikać z problemu scalenia lub pomieszanej myśli lub może to być rzeczywista intencja tego kodu, podczas gdy Pusta wyraźnie mówi mi, że deweloper zamierzał, aby ten ciąg nie zawierał danych.
Ritch Melton
3
Istnieje różnica między „” a ciągiem. Puste. Nie chodzi o to, że nikogo to obchodzi, ale „” tworzy obiekt, podczas gdy string.Empty korzysta z już utworzonego. Ale znowu jest tak mały, że tylko w szczególnych sytuacjach zrobiłoby to
różnicę
1
@ marcelo-ferrazm, about ""tworzy obiekt : Nie, nie robi.
Henk Holterman

Odpowiedzi:

271

Nie ma czegoś takiego jak pusty znak. Najbliżej można uzyskać '\0'znak zerowy Unicode. Biorąc pod uwagę, że możesz bardzo łatwo osadzić to w literałach łańcuchowych lub samodzielnie, dlaczego miałbyś chcieć dla niego osobnego pola? Podobnie argumenty „ łatwo pomylić ""i " "” nie mają zastosowania '\0'.

Jeśli możesz podać przykład, gdzie chcesz go użyć i dlaczego uważasz, że byłoby lepiej, może to pomóc ...

Jon Skeet
źródło
2
Czy \ 0 nie jest znakiem „końca tablicy bajtów”? A może mylę się z czymś innym?
Bertvan
5
@Bertvan: Dlaczego na końcu tablicy bajtów byłby znak ? Jest on używany do ciągów „zakończonych zerem”, tak.
Jon Skeet,
35
Char.MinValue jest lepszy niż „\ 0”
Aliostad
10
@Aliostad: Gdyby nie było zainteresowania, gdyby istniało podobne pole Int32.Zero, czy użyłbyś tego zamiast dosłownie 0? Jeśli nie, jaka jest tutaj różnica?
Jon Skeet,
7
@Adam, @Jon - jaki jest kod dzwonka? Albo cofnij się lepiej, pomyśl pomyśl ... A może zamiast myśleć, że lepiej jest napisać Char.Backspace? Kolejny powód - mówisz, że lepiej jest napisać „0” dla terminatora, zamiast tego, powiedz Char.Terminator, jednak tak nie jest - zbyt łatwo jest napisać literówkę (w pełni skompilowana, patrz wyżej), ale spróbuj napisać Char.Termnator. Jest wystarczająco dużo powodów, dla których muszę unikać surowych wartości, których nie da się sprawdzić, (misje kosmiczne zakończyły się niepowodzeniem z powodu takich głupich literówek).
greenoldman
87

Znak, w przeciwieństwie do łańcucha, jest dyskretną rzeczą o ustalonym rozmiarze. Sznurek jest naprawdę pojemnikiem znaków.

Tak więc Char.Empty tak naprawdę nie ma sensu w tym kontekście. Jeśli masz znak, nie jest pusty.

Joe
źródło
3
Dokładnie tak. Warto zapytać, czy pojemnik jest pusty, czy nie. Nie ma sensu pytać o int, float lub char is empty.
TED
1
@Joe: Jak więc łańcuch może być pusty, jeśli łańcuch jest zbiorem (niepustych) znaków? Prawdopodobnie głupie, przepraszam ...
user1477388 29.01.2013
9
Ponieważ ciąg nie jest pojedynczymi obiektami, jest kolekcją. Pomyśl o wiadrze skał. Nie mogę mieć pustej skały. Ale mogę mieć puste wiadro.
Joe
2
Wyraziłbym to jako „char jest prymitywnym typem wartości, a łańcuch nie jest prymitywnym typem referencyjnym”.
samis
3
To jest prawdziwa odpowiedź.
Gandalf458,
31

Nie ma czegoś takiego jak pusta postać. Zawsze coś zawiera . Nawet „\ 0” jest znakiem.

Philippe Leybaert
źródło
28

Użyj, Char.MinValuektóry działa tak samo jak „\ 0”. Ale bądź ostrożny, to nie to samo, co String.Empty.

Aliostad
źródło
Dzięki, nie widziałem tego wcześniej. Czy wiesz, czy to działa w myString.Replace ('c', Char.MinValue)? Powinienem spróbować.
Joan Venge
19

Możesz użyć zerowalnych znaków.

char? c
paquetp
źródło
To pozwala ''? A może po prostu zero?
Joan Venge
W twoim przypadku możesz to zrobić: myString.Replace ("c", (c == null? "": C.ToString ()))
paquetp
12

Jeśli nie potrzebujesz całego ciągu, możesz skorzystać z opóźnionego wykonania:

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

Możesz nawet łączyć wiele znaków ...

string veryLongText = "abcdefghijk...";

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

... i tylko pierwszych 7 znaków będzie ocenianych :)

EDYCJA: lub jeszcze lepiej:

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

i jego użycie:

        var veryLongText = "abcdefghijk...";
        IEnumerable<char> firstFiveCharsWithoutCsAndDs = veryLongText
            .RemoveChars('c', 'd')
            .Take(5)
            .ToArray(); //to prevent multiple execution of "RemoveChars"
Notoriousxl
źródło
@Joan: dzięki ... nawet jeśli „Geniusz” jest nieco przesadzony: P (nie wiem o jego osiągach po usunięciu Charów stanie się dużą tablicą ...)
Notoriousxl
1
Wczoraj zapomniałem: zwróć uwagę na to, jak używasz zmiennej wynikowej „firstFiveCharsWithoutCsAndDs”. Jeśli nie chcesz przekazać go innej metodzie „wydajności” (takiej jak LINQ), natychmiast wywołaj „.ToArray ()” po „Take (5)” ... w przeciwnym razie „RemoveChars + Take” łańcuch będzie wykonywany za każdym razem, gdy uzyskujesz dostęp do zmiennej w „tradycyjny” sposób (na przykład za każdym razem wywołujesz na niej „Count ()” lub gdy przechodzisz przez foreach bez „return return”)
Notoriousxl
+1 dobre myślenie. ale to nie może być tak
łatwe
1
@nawfal pod względem wydajności masz rację, ale myślę, że myString.Except („c”) jest bardziej deklaratywny niż myString.Replace ('c', ''): P (i skaluje się całkiem dobrze: myString.Except ( „aeiou”))
Notoriousxl
7
myString = myString.Replace('c'.ToString(), "");

OK, nie jest to szczególnie eleganckie do usuwania liter, ponieważ metoda .Replace ma przeciążenie, które przyjmuje parametry ciągu. Działa to jednak w przypadku usuwania znaków powrotu karetki, przesuwu linii, tabulatorów itp. Ten przykład usuwa znaki tabulacji:

myString = myString.Replace('\t'.ToString(), "");
Mike Taverne
źródło
6

z tego samego powodu nie ma int.Empty. Pojemniki mogą być puste. Wartości skalarne nie mogą być. Jeśli masz na myśli 0 (która nie jest pusta), użyj '\0'. Jeśli masz na myśli null, użyj null:)

dziesięć
źródło
2
wartość null nie jest możliwa, ponieważ char to ValueType. Musiałbyś użyć char? aby móc przypisać do niego wartość NULL.
Femaref
możesz sprawić, że będzie zerowy. patrz moja odpowiedź
paquetp,
5

Char jest typem wartości, więc jego wartość nie może być pusta. (Chyba że jest zapakowane w pojemnik Nullable).

Ponieważ nie może mieć wartości null, in zawiera trochę kodu numerycznego, a każdy kod jest odwzorowany na jakiś znak.

epotter
źródło
4

Nie jest to odpowiedź na twoje pytanie, ale jako domyślną charmożesz użyć tylko

default(char)

który jest taki sam jak ten, char.MinValuektóry z kolei jest taki sam jak \0. Nie należy jednak używać tego do pustych ciągów.

nawfal
źródło
1

Nie odpowiada na twoje pierwsze pytanie - ale w przypadku konkretnego problemu, który miałeś, możesz po prostu używać ciągów zamiast znaków, prawda ?:

myString.Replace("c", "")

Jest powód, dla którego nie chcesz tego robić?

Ian Grainger
źródło
1

Możesz także odbudować ciąg znaków po znaku, z wyłączeniem znaków, których chcesz się pozbyć.

Oto metoda rozszerzenia, aby to zrobić:

    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;
    }

Nie jest zręczny ani fantazyjny, ale działa dobrze.

Użyj w ten sposób:

string newString = "My_String".RemoveAny("_"); //yields "MyString"
C. Tewalt
źródło
Użyj StringBuilderdo result. Dlaczego nie owinąć return s.Replace(charsToRemove,"");?
aloisdg przechodzi na codidact.com
1

Jeśli chcesz usunąć znaki, które spełniają określony warunek, możesz użyć tego:

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

(Spowoduje to pozostawienie tylko wielkich liter w ciągu).

Innymi słowy, możesz „użyć” łańcucha jako IEnumerable<char>, wprowadzić w nim zmiany, a następnie przekonwertować go z powrotem na ciąg, jak pokazano powyżej.

Znowu ten pozwala nie tylko usunąć konkretny char ponieważ wyrażenia lambda, chociaż można to zrobić, jeśli zmienić wyrażenie lambda tak: c => c != 't'.

florien
źródło
0

Co powiesz na BOM , magiczną postać, którą Microsoft dodaje do początku plików (przynajmniej XML)?

Arto Viitanen
źródło
Sformułowanie w Wikipedii tutaj jest dość niefortunne; BOM nie jest w tym kontekście postacią. A jakie dokładnie jest twoje pytanie? :)
bzlm
@onemach, więc czy myString.Replace ('c', '')można to osiągnąć myString.Replace ('c', UTF_BOM). Powiedziałbym wtedy, że odpowiedź brzmi „jak nie o…”.
bzlm
0

jeśli chcesz wyeliminować pusty znak w ciągu, następujące działania będą działać, wystarczy przekonwertować na dowolną reprezentację typu danych, którą chcesz. dzięki,

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());
            }

        }

    }
Alexander Zaldostanov
źródło
0

Jeśli chodzi o język C #, poniższe mogą nie mieć większego sensu. I to nie jest bezpośrednia odpowiedź na pytanie. Ale fowlloing zrobiłem w jednym ze scenariuszy biznesowych

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

nullI white spacepłynie miał inny obiekt w moim projekcie. Podczas wstawiania do bazy danych muszę wstawiać empty stringdo bazy danych, jeśli jest to spacja.

LCJ
źródło
0

Wiem, że ten jest dość stary, ale ostatnio napotkałem problem z koniecznością wielokrotnego zastępowania, aby nazwa pliku była bezpieczna. Po pierwsze, w najnowszym ciągu .NET Funkcja zamiany null jest równoważna pustemu znakowi. Powiedziawszy to, brakuje w .Net prostego zastąpienia wszystkich, które zastąpią dowolny znak w tablicy żądanym znakiem. Zachęcamy do zapoznania się z poniższym kodem (działa w LinqPad do testowania).

// 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));
        }

    }

}
Jim
źródło
-3

posługiwać się

myString.Replace ("c", "")
Chintan
źródło
2
Jest to kopia odpowiedzi Iana Graingera z 2013 roku.
Joe Gayetty
-3

Najłatwiejszym sposobem na usunięcie koca z łańcucha znaków jest Przytnij go

cl = cl.Trim(' ');

Usuwa wszystkie spacje w ciągu

MrSmudge
źródło
Jest to pomocne, jeśli chce się użyć use .Replace ('c', '') z wadą usuwania innych białych znaków. Ale jest to bardziej pomocne niż wiele innych udzielonych odpowiedzi.
Jan
1
Nie, to źle! Przycinanie usuwa tylko znaki z początku i końca łańcucha, który nie jest w środku
userSteve