Jak usunąć wszystkie znaki alfanumeryczne z ciągu oprócz myślnika?


606

Jak usunąć z łańcucha wszystkie znaki niealfanumeryczne oprócz znaków myślnika i spacji?

Odpowiedzi:


870

Zamień [^a-zA-Z0-9 -]na pusty ciąg.

Regex rgx = new Regex("[^a-zA-Z0-9 -]");
str = rgx.Replace(str, "");

79
Warto wspomnieć, że -musi on znajdować się na końcu klasy postaci lub uciec z odwrotnym ukośnikiem, aby zapobiec użyciu dla zakresu.
Peter Boughton,

6
@Dan ustaw globalną flagę w wyrażeniu regularnym - bez tego po prostu zastępuje pierwsze dopasowanie. Szybki Google powinien powiedzieć, jak ustawić flagę globalną w klasycznym wyrażeniu regularnym ASP. W przeciwnym razie poszukaj replaceAllfunkcji zamiast replace.
Amarghosh,

20
Oto skompilowana wersja wyrażenia regularnego: To return Regex.Replace(str, "[^a-zA-Z0-9_.]+", "", RegexOptions.Compiled); samo podstawowe pytanie
Paige Watson

13
@MGOwen, ponieważ za każdym razem, gdy używasz „”, tworzysz nowy obiekt, ponieważ ciągi są niezmienne. Kiedy używasz string.empty, ponownie używasz pojedynczej instancji wymaganej do przedstawienia pustego ciągu, który jest szybszy, a także bardziej wydajny.
Brian Scott,

17
@BrianScott Wiem, że to jest stare, ale zostało znalezione podczas wyszukiwania, więc uważam, że jest to istotne. To zależy od wersji .NET, na której pracujesz. > 2.0 używa ""i string.Emptydokładnie tak samo. stackoverflow.com/questions/151472/…
Jared

348

Mógłbym użyć RegEx, mogą zapewnić eleganckie rozwiązanie, ale mogą powodować problemy z wydajnością. Oto jedno rozwiązanie

char[] arr = str.ToCharArray();

arr = Array.FindAll<char>(arr, (c => (char.IsLetterOrDigit(c) 
                                  || char.IsWhiteSpace(c) 
                                  || c == '-')));
str = new string(arr);

Podczas korzystania z kompaktowego frameworka (który nie ma FindAll)

Zamień FindAll na 1

char[] arr = str.Where(c => (char.IsLetterOrDigit(c) || 
                             char.IsWhiteSpace(c) || 
                             c == '-')).ToArray(); 

str = new string(arr);

1 komentarz ShawnFeatherly


41
w moich testach ta technika była znacznie szybsza. mówiąc dokładniej, było to prawie 3 razy szybciej niż technika Regex Replace.
Dan

12
Kompaktowy framework nie ma FindAll, możesz zastąpić FindAllchar[] arr = str.Where(c => (char.IsLetterOrDigit(c) || char.IsWhiteSpace(c) || c == '-')).ToArray();
ShawnFeatherly

2
czy ktoś to przetestował? To w ogóle nie działało. - ale zrobiło to dla mnie: ciąg str2 = nowy ciąg (str.Where (c => (char.IsLetterOrDigit (c))). ToArray ());
KevinDeus

48

Możesz spróbować:

string s1 = Regex.Replace(s, "[^A-Za-z0-9 -]", "");

Gdzie sjest twój sznurek?


1
OP poprosił o kreskę, a nie podkreślenie
Sean B

39

Korzystanie z System.Linq

string withOutSpecialCharacters = new string(stringWithSpecialCharacters.Where(c =>char.IsLetterOrDigit(c) || char.IsWhiteSpace(c) || c == '-').ToArray());

@Michael Jest podobny, ale przynajmniej jest to jedna linijka, a nie 3 linie. Powiedziałbym, że to wystarczy, aby zmienić odpowiedź.
Dymas,

1
@Dymas Zgadzam się teraz, że jest to dopuszczalne, ale nie dlatego, że biała spacja jest inna. Najwyraźniej część, która jest funkcjonalnie równoważna (różnią się tylko nazwy var), została edytowana po napisaniu tej odpowiedzi.
Michael - Where's Clay Shirky

1
@ZainAli, jeśli zrobisz trywialną edycję i pingujesz mnie, odwrócę moją opinię. Przepraszam za wszelkie insynuacje plagiarne.
Michael - Where's Clay Shirky

22

Wyrażenie regularne to [^\w\s\-]*:

\slepiej jest używać zamiast spacji ( ), ponieważ w tekście może znajdować się tabulator.


1
chyba że chcesz usunąć karty.
Matt Ellen,

... i znaki nowej linii oraz wszystkie inne znaki uważane za „białe znaki”.
Peter Boughton,

6
To rozwiązanie jest znacznie lepsze niż powyższe, ponieważ obsługuje także znaki międzynarodowe (nieanglojęzyczne). <! - language: c # -> string s = "Mötley Crue 日本人: の 氏 名 i Kanji 愛 i Hiragana あ い"; string r = Regex.Replace (s, "[^ \\ w \\ s -] *", ""); Powyższe tworzy r z: Mötley Crue 日本人 の 氏 名 i Kanji 愛 i Hiragana あ い
danglund

1
Użyj @, by uciec \ konwersji w ciągu: @ "[^ \ w \ s -] *"
Jakub Pawliński

1
to nie usuwa podkreślników? który jest uważany za „słowo” przez implementację wyrażenia regularnego w całym stworzeniu, ale nie jest alfanumeryczny, myślnikiem ani spacją… (?)
Code Jockey

14

Na podstawie odpowiedzi na to pytanie utworzyłem klasę statyczną i dodałem je. Pomyślałem, że może być przydatny dla niektórych osób.

public static class RegexConvert
{
    public static string ToAlphaNumericOnly(this string input)
    {
        Regex rgx = new Regex("[^a-zA-Z0-9]");
        return rgx.Replace(input, "");
    }

    public static string ToAlphaOnly(this string input)
    {
        Regex rgx = new Regex("[^a-zA-Z]");
        return rgx.Replace(input, "");
    }

    public static string ToNumericOnly(this string input)
    {
        Regex rgx = new Regex("[^0-9]");
        return rgx.Replace(input, "");
    }
}

Następnie metody mogą być użyte jako:

string example = "asdf1234!@#$";
string alphanumeric = example.ToAlphaNumericOnly();
string alpha = example.ToAlphaOnly();
string numeric = example.ToNumericOnly();

2
W podanym przykładzie przydatne byłoby również podanie wyników każdej z metod.
c-chavez

7

Chcesz coś szybko?

public static class StringExtensions 
{
    public static string ToAlphaNumeric(this string self, params char[] allowedCharacters)
    {
        return new string(Array.FindAll(self.ToCharArray(), c => char.IsLetterOrDigit(c) || allowedCharacters.Contains(c)));
    }
}

To pozwoli ci określić, na które znaki chcesz również zezwolić.


5

Oto szybkie, przyjazne dla alokacji stosów rozwiązanie, które właśnie tego szukałem.

Niebezpieczna edycja.

public static unsafe void ToAlphaNumeric(ref string input)
{
    fixed (char* p = input)
    {
        int offset = 0;
        for (int i = 0; i < input.Length; i++)
        {
            if (char.IsLetterOrDigit(p[i]))
            {
                p[offset] = input[i];
                offset++;
            }
        }
        ((int*)p)[-1] = offset; // Changes the length of the string
        p[offset] = '\0';
    }
}

I dla tych, którzy nie chcą używać niebezpiecznych lub nie ufają hackowi długości łańcucha.

public static string ToAlphaNumeric(string input)
{
    int j = 0;
    char[] newCharArr = new char[input.Length];

    for (int i = 0; i < input.Length; i++)
    {
        if (char.IsLetterOrDigit(input[i]))
        {
            newCharArr[j] = input[i];
            j++;
        }
    }

    Array.Resize(ref newCharArr, j);

    return new string(newCharArr);
}

4

Stworzyłem inne rozwiązanie, eliminując Kontrolę postacie , co było moim pierwotnym problemem.

To lepsze niż umieszczanie na liście wszystkich „specjalnych, ale dobrych” znaków

char[] arr = str.Where(c => !char.IsControl(c)).ToArray();    
str = new string(arr);

to jest prostsze, więc myślę, że jest lepiej!


2

Oto metoda rozszerzenia wykorzystująca odpowiedź @ata jako inspirację.

"hello-world123, 456".MakeAlphaNumeric(new char[]{'-'});// yields "hello-world123456"

lub jeśli potrzebujesz dodatkowych znaków innych niż łącznik ...

"hello-world123, 456!?".MakeAlphaNumeric(new char[]{'-','!'});// yields "hello-world123456!"


public static class StringExtensions
{   
    public static string MakeAlphaNumeric(this string input, params char[] exceptions)
    {
        var charArray = input.ToCharArray();
        var alphaNumeric = Array.FindAll<char>(charArray, (c => char.IsLetterOrDigit(c)|| exceptions?.Contains(c) == true));
        return new string(alphaNumeric);
    }
}

1

Używam tutaj wariantu jednej z odpowiedzi. Chcę zastąpić spacje znakiem „-”, więc jest przyjazny dla SEO, a także tworzy małe litery. Również nie odwołuje się do system.web z mojej warstwy usług.

private string MakeUrlString(string input)
{
    var array = input.ToCharArray();

    array = Array.FindAll<char>(array, c => char.IsLetterOrDigit(c) || char.IsWhiteSpace(c) || c == '-');

    var newString = new string(array).Replace(" ", "-").ToLower();
    return newString;
}


-1

Jest o wiele łatwiejszy sposób z Regex.

private string FixString(string str)
{
    return string.IsNullOrEmpty(str) ? str : Regex.Replace(str, "[\\D]", "");
}

1
zastępuje tylko znaki nienumeryczne
frostymarvelous
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.