Usuwanie znaków nienumerycznych w ciągu

Odpowiedzi:

237

Jest wiele sposobów, ale to powinno wystarczyć (nie wiem jednak, jak to działa z naprawdę dużymi ciągami znaków):

private static string GetNumbers(string input)
{
    return new string(input.Where(c => char.IsDigit(c)).ToArray());
}
Fredrik Mörk
źródło
21
Prawdopodobnie powinieneś IsDigitraczej użyć niż IsNumber: "Ta metoda [ IsNumber] określa, czy a Charnależy do dowolnej numerycznej kategorii Unicode. Oprócz cyfr, liczby obejmują znaki, ułamki, indeksy dolne, indeksy górne, cyfry rzymskie, liczniki walut i liczby zakreślone. Ta metoda kontrastuje z IsDigitmetodą, która określa, czy a Charjest cyfrą dziesiętną ”. msdn.microsoft.com/en-us/library/yk2b3t2y.aspx
LukeH
2
@TrevorBrooks Przypuszczam, że możesz po prostu rozszerzyć warunki:input.Where(c => char.IsDigit(c) || char.IsWhiteSpace(c))
Fredrik Mörk,
6
Można to jeszcze bardziej uprościć return new string(input.Where(char.IsDigit).ToArray());. Po prostu
sprawiam,
2
Niezła odpowiedź. Warto po prostu rozważyć zmianę nazwy funkcji z „GetNumbers” na „GetDigits” ... aby jasno określić jej zamiar.
JTech
2
To także świetna metoda przedłużania.
Roberto Bonini
61

Wygląda na to, że dobrze pasuje do wyrażenia regularnego.

var s = "40,595 p.a.";
var stripped = Regex.Replace(s, "[^0-9]", "");

"[^0-9]"można zastąpić, @"\D"ale podoba mi się czytelność [^0-9].

Jonas Elfström
źródło
1
Zgadzam się, o ile nie
przeszkadza ci
4
Z ciekawości, jaka jest wydajność między tą odpowiedzią a odpowiedzią Fredrika Morka?
Scuba Steve
Jest to prawdopodobnie wolniejsze, ale jedynym sposobem na poznanie jest pomiar, ponieważ zależy to od tego, jak .NET implementuje wyrażenia regularne, jak jest kompilowane Lambda Expression i nie tylko.
Jonas Elfström
1
Jest to bardziej elastyczne niż użycie IsDigit (), ponieważ można dodać „.” znaków do wyrażenia regularnego, jeśli chcesz zezwolić na liczby z miejscami dziesiętnymi.
Richard Moore
10
Zrobiłem proste porównanie Regex vs. LINQ na ciągu złożonym z 100 000 połączonych identyfikatorów GUID (w wyniku czego powstał ciąg 3 600 000 znaków). Regex był konsekwentnie około pół sekundy, podczas gdy LINQ konsekwentnie znajdował się w 1/10 drugiego zakresu. Zasadniczo LINQ był średnio 5 lub więcej razy szybszy.
Chris Pratt
8

Metoda rozszerzenia będzie lepszym podejściem:

public static string GetNumbers(this string text)
    {
        text = text ?? string.Empty;
        return new string(text.Where(p => char.IsDigit(p)).ToArray());
    }
Ercan Ayan
źródło
Wolę if (text == null) return string.Empty;więcej text = text ?? string.Empty;. W ten sposób nie zmniejszamy wydajności.
Hooman,
6

Użyj dowolnego wyrażenia regularnego, które przechwytuje tylko 0-9, a resztę odrzuca. Jednak wyrażenie regularne to operacja, która za pierwszym razem będzie dużo kosztować. Lub zrób coś takiego:

var sb = new StringBuilder();
var goodChars = "0123456789".ToCharArray();
var input = "40,595";
foreach(var c in input)
{
  if(goodChars.IndexOf(c) >= 0)
    sb.Append(c);
}
var output = sb.ToString();

Myślę, że coś takiego nie skompilowałem ...

LINQ jest, jak powiedział Fredrik, również opcją

Onkelborg
źródło
4

Inna opcja ...

private static string RemoveNonNumberDigitsAndCharacters(string text)
{
    var numericChars = "0123456789,.".ToCharArray();
    return new String(text.Where(c => numericChars.Any(n => n == c)).ToArray());
}
kernowcode
źródło
2
a co z negatywem? (-) czy minus nie powinien być poza tym?
Seabizkit
3
public static string RemoveNonNumeric(string value) => Regex.Replace(value, "[^0-9]", "");
Patrick Cairns
źródło
to zadziała, gdy pozwolę na ułamki dziesiętne.
John Lord
0

Wiesz, jakie są cyfry: 0123456789, prawda? Przemierzaj łańcuch znak po znaku; jeśli znak jest cyfrą, przyklej go do końca łańcucha tymczasowego, w przeciwnym razie zignoruj. Mogą istnieć inne metody pomocnika dostępne dla ciągów C #, ale jest to podejście ogólne, które działa wszędzie.

Tim
źródło
0

Oto kod wykorzystujący wyrażenia regularne:

string str = "40,595 p.a.";

StringBuilder convert = new StringBuilder();

string pattern = @"\d+";
Regex regex = new Regex(pattern);

MatchCollection matches = regex.Matches(str);

foreach (Match match in matches)
{
convert.Append(match.Groups[0].ToString());
}

int value = Convert.ToInt32(convert.ToString()); 
dhirschl
źródło
Co muszę zrobić, aby uzyskać Regex Working i ten błąd Nazwa „Regex” nie istnieje w bieżącym kontekście
StevieB
using System.Text.RegularExpressions;
dhirschl
0

Przyjęta odpowiedź jest świetna, jednak nie bierze pod uwagę wartości NULL, przez co jest bezużyteczna w większości scenariuszy.

To skłoniło mnie do korzystania z tych metod pomocniczych. Pierwsza odpowiada na PO, podczas gdy inne mogą być przydatne dla tych, którzy chcą zrobić coś odwrotnego:

    /// <summary>
    /// Strips out non-numeric characters in string, returning only digits
    /// ref.: /programming/3977497/stripping-out-non-numeric-characters-in-string
    /// </summary>
    /// <param name="input">the input string</param>
    /// <param name="throwExceptionIfNull">if set to TRUE it will throw an exception if the input string is null, otherwise it will return null as well.</param>
    /// <returns>the input string numeric part: for example, if input is "XYZ1234A5U6" it will return "123456"</returns>
    public static string GetNumbers(string input, bool throwExceptionIfNull = false)
    {
        return (input == null && !throwExceptionIfNull) 
            ? input 
            : new string(input.Where(c => char.IsDigit(c)).ToArray());
    }

    /// <summary>
    /// Strips out numeric and special characters in string, returning only letters
    /// </summary>
    /// <param name="input">the input string</param>
    /// <param name="throwExceptionIfNull">if set to TRUE it will throw an exception if the input string is null, otherwise it will return null as well.</param>
    /// <returns>the letters contained within the input string: for example, if input is "XYZ1234A5U6~()" it will return "XYZAU"</returns>
    public static string GetLetters(string input, bool throwExceptionIfNull = false)
    {
        return (input == null && !throwExceptionIfNull) 
            ? input 
            : new string(input.Where(c => char.IsLetter(c)).ToArray());
    }

    /// <summary>
    /// Strips out any non-numeric/non-digit character in string, returning only letters and numbers
    /// </summary>
    /// <param name="input">the input string</param>
    /// <param name="throwExceptionIfNull">if set to TRUE it will throw an exception if the input string is null, otherwise it will return null as well.</param>
    /// <returns>the letters contained within the input string: for example, if input is "XYZ1234A5U6~()" it will return "XYZ1234A5U6"</returns>
    public static string GetLettersAndNumbers(string input, bool throwExceptionIfNull = false)
    {
        return (input == null && !throwExceptionIfNull) 
            ? input 
            : new string(input.Where(c => char.IsLetterOrDigit(c)).ToArray());
    }

Aby uzyskać dodatkowe informacje, przeczytaj ten post na moim blogu.

Darkseal
źródło
-1
 var output = new string(input.Where(char.IsNumber).ToArray());
Emre Sevim
źródło