Como você pode extrair caracteres não ASCII de uma string? (em c #)

227

Como você pode extrair caracteres não ASCII de uma string? (em c #)

philcruz
fonte
4
Por resposta de sinelaw abaixo , se você em vez disso quer substituir caracteres não-ASCII, veja esta resposta vez .
Bobson

Respostas:

414
string s = "søme string";
s = Regex.Replace(s, @"[^\u0000-\u007F]+", string.Empty);
philcruz
fonte
19
Para aqueles de nós que a RegEx desafiou, você se importaria de escrever em inglês puro seu padrão RegEx. Em outras palavras, "o ^ faz isso", etc ...
Metro Smurf
47
@ Smurf Metro o ^ não é o operador. Diz ao regex para encontrar tudo o que não corresponde, em vez de tudo o que corresponde. O \ u #### - \ u #### indica quais caracteres correspondem. \ U0000- \ u007F é o equivalente aos 255 primeiros caracteres em utf-8 ou unicode, que são sempre os caracteres ascii. Então você combina todos os caracteres não ascii (por causa do not) e substitui tudo o que corresponde.
21137 Gordon Tucker
41
Faixa de caracteres imprimíveis é 0020-007E, para pessoas que procuram expressão regular para substituir caracteres não imprimíveis
Mubashar
1
@GordonTucker \ u0000- \ u007F é o equivalente dos primeiros 127 caracteres em utf-8 ou unicode e NÃO é o primeiro 225. Consulte a tabela
full_prog_full
4
@full_prog_full É por isso que eu respondi a mim mesmo cerca de um minuto depois corrigir-me a dizer que foi 127 e não 255. :)
Gordon Tucker
125

Aqui está uma solução .NET pura que não usa expressões regulares:

string inputString = "Räksmörgås";
string asAscii = Encoding.ASCII.GetString(
    Encoding.Convert(
        Encoding.UTF8,
        Encoding.GetEncoding(
            Encoding.ASCII.EncodingName,
            new EncoderReplacementFallback(string.Empty),
            new DecoderExceptionFallback()
            ),
        Encoding.UTF8.GetBytes(inputString)
    )
);

Pode parecer complicado, mas deve ser intuitivo. Ele usa a codificação .NET ASCII para converter uma string. O UTF8 é usado durante a conversão porque pode representar qualquer um dos caracteres originais. Ele usa um EncoderReplacementFallback para converter qualquer caractere não ASCII em uma sequência vazia.

bzlm
fonte
5
Perfeito! Estou usando isso para limpar uma string antes de salvá-la em um documento RTF. Muito apreciado. Muito mais fácil de entender do que a versão Regex.
18419 Nathan Prather
21
Você realmente acha mais fácil entender? Para mim, todas as coisas que não são realmente relevantes (fallbacks, conversões em bytes etc.) estão desviando a atenção do que realmente acontece.
22239 bzlm
21
É como dizer que chaves de fenda são muito confusas, então eu vou usar um martelo.
Brandon
8
@Brandon, na verdade, essa técnica não funciona melhor do que outras técnicas. Assim, a analogia seria usando uma chave de fenda olde simples ao invés de uma fantasia iScrewDriver deluxe 2000. :)
bzlm
10
Uma vantagem é que pode facilmente substituir ASCII com a norma ISO 8859-1 ou outra codificação :)
Akira Yamamoto
38

Acredito que MonsCamus quis dizer:

parsememo = Regex.Replace(parsememo, @"[^\u0020-\u007E]", string.Empty);
Josh
fonte
1
IMHO Esta resposta é melhor que a resposta aceita, porque retira os caracteres de controle.
precisa saber é o seguinte
15

Se você não deseja despir, mas realmente converter caracteres acentuados em latim em caracteres não acentuados, dê uma olhada nesta pergunta: Como converter caracteres de 8 bits em caracteres de 7 bits? (ie Ü a U)

sinelaw
fonte
Eu nem percebi que isso era possível, mas é uma solução muito melhor para mim. Vou adicionar este link a um comentário sobre a pergunta para facilitar a localização de outras pessoas. Obrigado!
Bobson
11

Inspirado na solução Expression Regular da philcruz, criei uma solução LINQ pura

public static string PureAscii(this string source, char nil = ' ')
{
    var min = '\u0000';
    var max = '\u007F';
    return source.Select(c => c < min ? nil : c > max ? nil : c).ToText();
}

public static string ToText(this IEnumerable<char> source)
{
    var buffer = new StringBuilder();
    foreach (var c in source)
        buffer.Append(c);
    return buffer.ToString();
}

Este é um código não testado.

Bent Rasmussen
fonte
1
Para quem não entendeu, esta é uma solução baseada em LINQ em C # 4.0. :)
7
Em vez do método ToText () separado, que tal substituir a linha 3 de PureAscii () por: return new string (source.Select (c => c <min? Nil: c> max? Nil: c) .ToArray ()) ;
agentnega
Ou talvez ToText como: return (nova string (fonte)). ToArray () - dependendo do que tiver melhor desempenho. Ainda é bom ter o ToText como método de extensão - estilo fluente / pipeline. :-)
Bent Rasmussen
Esse código substitui caracteres não ASCII por um espaço. Para return new string( source.Where( c => c >= min && c <= max ).ToArray() );
removê-
@Foozinator Esse código permite que você especifique qual caractere substituir os caracteres não ASCII. Por padrão, ele usa um espaço, mas se for chamado .PureASCII (Char.MinValue), substituirá todos os não-ASCII por '\ 0' - o que ainda não está exatamente excluindo-os, mas com resultados semelhantes.
Ulfius
5

não há necessidade de regex. basta usar codificação ...

sOutput = System.Text.Encoding.ASCII.GetString(System.Text.Encoding.ASCII.GetBytes(sInput));
rjp
fonte
5
Isso não funciona. Isso não tira caracteres unicode, substitui-os pelo? personagem.
David
1
@ David está certo. Pelo menos eu consegui ????nacho??quando tentei: たまねこnachoなちno mono 3.4
nacho4d
1
Você pode instanciar sua própria classe Encoding que, em vez de substituir caracteres, os remove. Veja o método GetEncoding: msdn.microsoft.com/en-us/library/89856k4b(v=vs.110).aspx
kkara
4

Eu achei o seguinte intervalo ligeiramente alterado útil para analisar blocos de comentários em um banco de dados, isso significa que você não precisará lidar com caracteres de tabulação e escape, o que causaria transtorno a um campo CSV.

parsememo = Regex.Replace(parsememo, @"[^\u001F-\u007F]", string.Empty);

Se você deseja evitar outros caracteres especiais ou pontuação específica, verifique a tabela ascii

MonsCamus
fonte
1
Caso alguém não tenha notado os outros comentários, os caracteres imprimíveis são realmente @ "[^ \ u0020- \ u007E]". Aqui está um link para ver a tabela se você está curioso: asciitable.com
scradam
3

Eu vim aqui procurando uma solução para caracteres ASCII estendidos, mas não consegui encontrá-la. O mais próximo que encontrei é a solução da bzlm . Mas isso funciona apenas para o código ASCII até 127 (obviamente, você pode substituir o tipo de codificação no código dele, mas acho que era um pouco complexo de entender. Por isso, compartilhando esta versão). Aqui está uma solução que funciona para códigos ASCII estendidos, ou seja, até 255, que é o ISO 8859-1

Encontra e remove caracteres não-ascii (maiores que 255)

Dim str1 as String= "â, ??î or ôu🕧� n☁i✑💴++$-💯♓!🇪🚑🌚‼⁉4⃣od;/⏬'®;😁☕😁:☝)😁😁///😍1!@#"

Dim extendedAscii As Encoding = Encoding.GetEncoding("ISO-8859-1", 
                                                New EncoderReplacementFallback(String.empty),
                                                New DecoderReplacementFallback())

Dim extendedAsciiBytes() As Byte = extendedAscii.GetBytes(str1)

Dim str2 As String = extendedAscii.GetString(extendedAsciiBytes)

console.WriteLine(str2)
'Output : â, ??î or ôu ni++$-!‼⁉4od;/';:)///1!@#$%^yz:

Aqui está um violino de trabalho para o código

Substitua a codificação conforme o requisito, o restante deve permanecer o mesmo.

Próton polinomial
fonte
2
O único que trabalhou para remover SOMENTE o Ω dessa string "Ω c ç ã". Muito obrigado!
Rafael Araújo
2

Isso não é ideal em termos de desempenho, mas uma abordagem bastante direta do Linq:

string strippedString = new string(
    yourString.Where(c => c <= sbyte.MaxValue).ToArray()
    );

A desvantagem é que todos os caracteres "sobreviventes" são primeiro colocados em uma matriz do tipo char[]que é descartada depois que o stringconstrutor não o usa mais.

Jeppe Stig Nielsen
fonte
1

Eu usei esta expressão regex:

    string s = "søme string";
    Regex regex = new Regex(@"[^a-zA-Z0-9\s]", (RegexOptions)0);
    return regex.Replace(s, "");
Covarde anônimo
fonte
16
Isso remove a pontuação também, caso isso não seja o que alguém deseja.
de Drew Noakes
1

Eu uso essa expressão regular para filtrar caracteres inválidos em um nome de arquivo.

Regex.Replace(directory, "[^a-zA-Z0-9\\:_\- ]", "")

Devem ser todos os caracteres permitidos para nomes de arquivos.

user890332
fonte
1
Não. Consulte Path.GetInvalidPathChars e Path.GetInvalidFileNameChars . Portanto, existem dezenas de milhares de caracteres válidos.
precisa
Você está correto, Tom. Na verdade, eu estava pensando nos comuns, mas deixei de fora parênteses e chaves, assim como tudo isso - ^% $ # @! & + =.
user890332