2010-02-22 5 views
6

format ciągów jest zawsze taki jak ten "FirstName = ABC; LastName = XZY; Username = User1; Password = 1234".jak do podciągu z ciągu przy użyciu C#?

Potrzebuję jedynej wartości UserName (w tym przypadku "User1"). Chcę to osiągnąć w minimalnej linii kodu używając metody podłańcuchowej (lub czegoś innego).

Pomoc?

+0

Kiedy problem ma bardzo ostatecznych odpowiedzi, takie jak ten to zawsze zabawne mnie oglądać jak wiele różnych rozwiązań SO wspólnotowe przewiduje. –

+0

Jedna rzecz do zapamiętania: ciąg wejściowy ma pole o nazwie "Użytkownik ** n ** nazwa". Następnie pytasz o pole "Użytkownik ** N ** ame". Uważaj na obudowę podczas analizowania łańcuchów. Są oczywiście sposoby na rozwiązanie tego problemu. –

Odpowiedz

4

Metoda ta działa nawet wtedy, gdy wartość par są podane w innej kolejności. Dzieli na średnik, znajduje element z "Username", a następnie zwraca to, co jest po znaku równości.

string theString = "FirstName=ABC;LastName=XZY;Username=User1;Password=1234"; 
string username = theString.Split(";").Where(s => s.Split("=")[0].Equals("Username")).ToArray()[0].Split("=")[1]; 
+0

@Aaron: Przepraszam, że pytam, czy jest składnia oke. Otrzymuję błąd w pobliżu .ToArray [0] .. ?? – Jango

+0

@ user144842: Wystąpił błąd w moim przykładzie! Po ToArray mają być nawiasy. Zaktualizowałem swoją odpowiedź. – Aaron

+0

To byłaby połowa VB i połowa C# ... prawdopodobnie wszystko z czubka jego głowy. –

12

Wygląda na ograniczony ciąg, więc to będzie działać:

string result = myString.Split(';')[2].Split('=')[1]; 

Jednakże, jeśli ktoś zmienia kolejność pary wartości, to złamie.

Są na to lepsze sposoby, które nie ulegną zerwaniu, jeśli zmieni się kolejność, liczba parametrów jest inna itd. - na przykład Wyrażenie regularne, jak napisał Michael, lub zapytania Linq publikowane przez pewną liczbę osób.

+0

Bicie mnie do tego :( –

+3

Doceniam, że starałeś się zrobić to jak najkrótszym, ale myślę, że mamy zwycięzcę dla najbrzydszego kawałka kodu jaki widziałem ostatnio (bez obrazy zamierzonej!) – brian

+0

Nie chciałbym "Mów jej najgorszy kod w historii, ale użytkownik dostał to, czego chciał ... –

4

Najmniejsza liczba linii kodu nie zawsze jest najlepszym wskaźnikiem, ale możesz zrobić to, czego potrzebujesz z Regeksem.

+1

To dziwne, prawdopodobnie jest to jedna z pierwszych okazji, w których kiedykolwiek widziałem sugerowane wyrażenie regularne i że jest to poprawna odpowiedź. : p – Tanzelax

+0

Nie słyszałeś - niektórzy ludzie, gdy napotykają problem, myślą: "Wiem, użyję wyrażeń regularnych". Teraz mają dwa problemy. Jamie Zawinski – Oded

+0

@Tanzelax: Regex staje się nowym JQuery? – brian

1
 string t = "FirstName=ABC;LastName=XZY;Username=User1;Password=1234"; 
     string name = t.Split(';')[2].Split('=')[1]; 
7

Oto alternatywne rozwiązanie (nie różni się zbytnio od innych, ale uważam, że jest prostsze), które zadziała niezależnie od zamówienia.

var input = "FirstName=ABC;LastName=XZY;Username=User1;Password=1234"; 

Assert.AreEqual("User1", input 
    .Split(';') 
    .Select(item => item.Split('=')) 
    .Where(pair => pair[0].Equals("Username")) 
    .Single()[1]); 
+0

Błąd w przypadku braku nazwy użytkownika w ciągu znaków. –

+0

Jeśli może nie być nazwy użytkownika, możesz dodać '.Select (pair => pair [1])' przed '.Single()' i zmienić '.Single()' na '.SingleOrDefault()'. Wtedy otrzymasz wartość null, jeśli nie ma nazwy użytkownika. –

15

Dla zachowania kompletności, tutaj jest Regex sposób robienia tego. Będzie to również działać, jeśli zamówienie się zmieni.

// using System.Text.RegularExpressions; 

string test1 = "FirstName=ABC;LastName=XZY;Username=User1;Password=1234"; 
string test2 = "FirstName=ABC;LastName=XZY;Password=1234;Username=User1"; 
string test3 = "FirstName=ABC;LastName=XZY;Password=1234"; 

string regexPattern = @"(?<=Username=)[^;\n]*"; 
var userName1 = Regex.Match(test1, regexPattern).Value; // User1 
var userName2 = Regex.Match(test2, regexPattern).Value; // User1 
var userName3 = Regex.Match(test3, regexPattern).Value; // string.Empty 

// Compiling can speed up the Regex, at the expense of longer initial Initialization 
// Use when this is called often, but measure. 

Regex compiledRx = new Regex(regexPattern,RegexOptions.Compiled); 
var userNameCompiled1 = compiledRx.Match(test1).Value; // User1 
var userNameCompiled2 = compiledRx.Match(test2).Value; // User1 
var userNameCompiled3 = compiledRx.Match(test3).Value; // string.Empty 
+1

To jest naprawdę dobre miejsce do zastosowania wyrażeń regularnych. Dobry towar. –

3

Podczas odpowiedzi podzielone są „ok”, jeśli nic się nie zmieni, to chyba lepiej użyć funkcji, ponieważ:

  • To sprawia, że ​​intencje jasne.
  • Łatwiej jest udokumentować.
  • Łatwiej jest modyfikować, jeśli stanie się to, co nieuniknione.
  • Działa bez względu na kolejność.

(Nawet jeśli po prostu umieścić podział jednego wiersza w funkcji lub przynajmniej dodać komentarz do podziału!).


static String GetUsername(String value) 
{ 
    String result = ""; 
    String token = "Username="; 

    int index = value.IndexOf(token) + token.Length; 
    while (value[index] != ';') 
    { 
     result += value[index++]; 
     if (index > value.Length - 1) 
      break; 
    } 

    return result; 
} 
+0

Podoba mi się sugestia, by zamknąć tę "logikę", ale bądźmy zła: jego próbka nie zakończyła się na ";". Teraz wyobraź sobie, że część "Username =" jest na końcu, co by się stało z twoim rozwiązaniem? –

+3

@Benjamin - Chociaż nie jest to trudne w obsłudze; Myślę, że wszystkie przedstawione rozwiązania cierpią na pewne niedociągnięcia. Na przykład, co jeśli w łańcuchu są dwie nazwy użytkownika? Co by się stało? To rozwiązanie zawsze wybierze pierwsze. W każdym razie myślę, że ten banalny problem został doprowadzony do skrajności. –

+0

Zgoda - i +1 za to :) –

3

nie tak proste, jak przy użyciu podział, jednakże:

string input = "FirstName=ABC;LastName=XZY;Username=User1;Password=1234"; 
string username = Regex.Match(input, "Username=(?<username>.*?)(;|$)").Groups["username"].Value; 

W tym przypadku grupy mogą być w dowolnej kolejności.

A jeśli chcesz dostać twórczy:

var answers = from tuple in input.Split(';') 
       where tuple.StartsWith("Username=") 
       select tuple.Split('=')[1]; 

username = answers.Count() > 0 ? answers.First() : string.Empty; 

Można by powiedzieć, że ostatni kawałek ma lepsze semantykę.

EDYCJA: Zaktualizuj ostatni element, aby poradzić sobie z ciągami wejściowymi, które nie mają wymaganej krotki.

+0

Zepsuje się, jeśli ciąg źródłowy to 'FirstName = ABC, Username = User1; LastName = XZY; Password = 1234'. Użyj '' 'dla leniwego wyszukiwania:' Nazwa użytkownika = (? . *?); ' –

+0

@Naeem Sarfraz: Dzięki, masz rację. Cholerna chciwa rzecz. Przekłamałem też przypadek, w którym nazwa użytkownika jest ostatnią parą w ciągu znaków. A teraz REGEX jest skomplikowany ... –

1

To nie jest najkrótsza ... ale prawdopodobnie jedna z najszybszych.

string value = "FirstName=ABC;LastName=XZY;Username=User1;Password=1234"; 
int offset = value.IndexOf("Username=") + 9; 
if (offset < 9) 
    throw new Exception("Username= not found in string"); 
int len = value.IndexOf(';', offset) - offset; 
if (len < 0) 
    len = value.Length - offset; 
string find = value.Substring(offset, len); 

... The if (len < 0) jest to Nazwa jest na końcu łańcucha i nie kończy się średnikiem. Jeśli chcesz zignorować sprawę można zamienić linię int offset z tym ...

int offset = value.ToUpperInvariant().IndexOf("USERNAME=") + 9; 
+0

Wiem, że "magiczną liczbę" można zastąpić przez przeniesienie "Username =" do zmiennej, takiej jak token i użycie tokenu. Długość. –

+0

Możesz narzekać na "wyjątek" Nie czułem się na niczym lepszym niż na przykład. –

Powiązane problemy