2010-04-05 10 views
12

Używam natywnego natywnego API, w którym wysyłam wskaźnik bufora niepewnych bajtów, aby uzyskać wartość ciągów znaków.Pomoc z 0 zakończonymi łańcuchami w C#

Więc to daje mi

// using byte[255] c_str 
string s = new string(Encoding.ASCII.GetChars(c_str)); 

// now s == "heresastring\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0(etc)"; 

Tak oczywiście nie robię to dobrze, w jaki sposób pozbyć się nadmiaru?

+0

Mam coś podobnego, gdy otrzymałem ciąg przez RS-232. W końcu zrobiłem to źle: odkryłem, że program obsługi jest wywoływany dla każdego otrzymanego bajtu, a w programie obsługi użyłem "serialPortInstance.Read (...)", aby przeczytać więcej niż 1 bajt. – Dor

+0

Nie jestem pewien, ale mogę rzucić okiem na RegularExpression, coś jak ciąg re1 = "((?: [A-z] [a-z] +))"; i uzyskaj pierwszy mecz –

+0

"Reguła" łańcuchów zakończonych znakiem pustym jest taka, że ​​* wszystko * zaczynające się od pierwszej wartości zerowej powinno zostać zignorowane. Kilka innych odpowiedzi, które po prostu Trim() lub Replace() nie biorą pod uwagę, że po początkowej wartości zerowej mogą występować pewne "puste wiadomości" o wartości zerowej. [Ta odpowiedź] (https://stackoverflow.com/a/35182252/1633949) daje rozwiązanie jednokreskowe. –

Odpowiedz

0

Wierzę, że \ 0 jest "null" w ascii - czy jesteś pewien, że ciąg, który otrzymujesz, jest w rzeczywistości zakodowany w ASCII?

+0

Myślę, że oznacza on, że otrzymuje serię bajtów zerowych, a nie że faktycznie otrzymuje ciąg znaków "\ 0". – Randolpho

+0

Tak, to ASCII – y2k

+0

Zgaduję, że się podoba .Trim ("\ 0") haha ​​ – y2k

5

Może istnieć opcja usunięcia elementów NUL w konwersji.

Poza tym, prawdopodobnie można go oczyścić z:

s = s.Trim('\0'); 

... lub, jeśli myślisz, że nie może być non-NUL znaki po pewnym nuls, może to być bezpieczniej:

int pos = s.IndexOf('\0'); 
if (pos >= 0) 
    s = s.Substring(0, pos); 
28

Łańcuchy .NET nie są zakończone znakiem NUL (jak można się domyślić). Możesz więc traktować "\ 0", tak jak traktujesz każdą normalną postać. Normalna manipulacja ciągami naprawi wszystko za Ciebie. Oto niektóre (ale nie wszystkie) opcje.

s = s.Trim('\0'); 

s = s.Replace("\0", ""); 

var strings = s.Split(new char[] {'\0'}, StringSplitOptions.RemoveEmptyEntries); 

Jeśli na pewno chcesz wyrzucić wszystkie wartości po pierwszym znaku pustym, może to być lepsze dla Ciebie. Ale bądź ostrożny, działa tylko na ciągach, które faktycznie zawierają znak null.

s = s.Substring(0, Math.Max(0, s.IndexOf('\0'))); 
+0

Podejścia te polegają na tym, że mogą występować znaki inne niż null po pierwszej null w ciągu znaków. [Ta odpowiedź] (https://stackoverflow.com/a/35182252/1633949) daje bardziej niezawodne rozwiązanie. –

+0

Hm ... jak to jest w przypadku każdego z tych podejść brakujące znaki po wartościach zerowych? Trim działa tylko na końcach strun. Replace nie robi nic dla żadnej części ciągu, z wyjątkiem znaku pustego.Split jawnie przechowuje wszystko poza znakiem pustym, tworząc tablicę łańcuchów. Wygląda na to, że każda opcja bezpiecznie obsługuje każdy nie-pusty znak w dowolnym ciągu. –

+0

Twoje rozwiązania sprawdzają się w przypadku konkretnego ciągu znaków OP. Ale ciągi zwracane z natywnego (C++) API mogą zawierać śmieci po początkowej wartości null. Ogólne rozwiązanie musi zignorować wszystko po początkowej wartości zerowej, a nie tylko pominąć wartość zerową. Wypróbuj każde z rozwiązań na tym przykładowym łańcuchu znaków ("Oto ciąg \ 0memoryjunkhere"), aby zobaczyć, co mam na myśli. –

2

Co z jedną z metod System.Runtime.InteropServices.Marshall.PtrToString*?

Marshal.PtrToStringAnsi - Kopiuje wszystkie znaki do pierwszego pustego znaku z niezarządzanego ciągu ANSI do zarządzanego ciągu znaków i rozszerza każdy znak ANSI do Unicode.

Marshal.PtrToStringUni - Przydziela zarządzany ciąg i kopiuje do niego całą lub część do pierwszej wartości null niezarządzanego ciągu znaków Unicode.

2
// s == "heresastring\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0(etc)"  
s = s.Split(new[] { '\0' }, 2)[0]; 
// s == "heresastring"