Regex para remover tudo (não numérico OU período)

93

Preciso que um texto como "joe ($ 3.004,50)" seja filtrado para 3004,50, mas sou péssimo em regex e não consigo encontrar uma solução adequada. Portanto, apenas números e períodos devem permanecer - todo o resto filtrado. Eu uso o framework C # e VS.net 2008 3.5

Ready Cent
fonte

Respostas:

166

Isso deve servir:

string s = "joe ($3,004.50)";
s = Regex.Replace(s, "[^0-9.]", "");
josephj1989
fonte
1
Sobre o quê joe.smith ($3,004.50)? Simplesmente remover classes de personagens ofensivas pode dar errado.
Matthew Gunn
2
Eu faço uma pequena correção: Regex.Replace(s, "[^$0-9.]", "");você quer deixar o cifrão.
bodacydo
35

O regex é:

[^0-9.]

Você pode armazenar em cache o regex:

Regex not_num_period = new Regex("[^0-9.]")

então use:

string result = not_num_period.Replace("joe ($3,004.50)", "");

No entanto, você deve ter em mente que algumas culturas têm convenções diferentes para escrever valores monetários, como: 3,004,50.

Matthew Flaschen
fonte
ATM com preguiça de verificar, mas você não precisa escapar do. ?
Andrew Anderson
7
@Andrew: não, dentro de uma classe de personagem, .não tem nenhum significado especial.
Bart Kiers
2

Para a resposta aceita, MatthewGunn levanta um ponto válido em que todos os dígitos, vírgulas e pontos na string inteira serão condensados ​​juntos. Isso evitará que:

string s = "joe.smith ($3,004.50)";
Regex r = new Regex(@"(?:^|[^w.,])(\d[\d,.]+)(?=\W|$)/)");
Match m = r.match(s);
string v = null;
if (m.Success) {
  v = m.Groups[1].Value;
  v = Regex.Replace(v, ",", "");
}
mindriot
fonte
Parece que o regex acima tem parênteses extras. Usar (?:^|[^w.,])(\d[\d,.]+)(?=\W|$)também corresponderá a "h25" na string "joe.smith25 ($ 3.004,50)"
Rivka
1

A abordagem de remover personagens ofensivos é potencialmente problemática. E se houver outro .na corda em algum lugar? Não será removido, embora deva!

Removendo não dígitos ou pontos, a string joe.smith ($3,004.50)se transformaria no não analisável .3004.50.

Imho, é melhor corresponder a um padrão específico e extraí-lo usando um grupo. Algo simples seria encontrar todas as vírgulas, dígitos e pontos contíguos com regexp:

[\d,\.]+

Teste de amostra executado:

Pattern understood as:
[\d,\.]+
Enter string to check if matches pattern
>  a2.3 fjdfadfj34  34j3424  2,300 adsfa    
Group 0 match: "2.3"
Group 0 match: "34"
Group 0 match: "34"
Group 0 match: "3424"
Group 0 match: "2,300"

Em seguida, para cada correspondência, remova todas as vírgulas e envie para o analisador. Para lidar com o caso de algo como 12.323.344, você pode fazer outra verificação para ver se uma substring correspondente tem no máximo um ..

Matthew Gunn
fonte
Esta regex corresponde a tudo.
mindriot
Agora corresponde a tudo, exceto "".
mindriot
1
O conceito que você está propondo exigiria um regex complexo que é difícil de ler e depurar. Pode ser melhor dividi-lo em etapas com várias regex e condicionais. Eu poderia fornecer uma resposta (embora escrita em Ruby como não sei c #.
mindriot
@mindriot Ponto tomado. Mudei para algo mais transparente.
Matthew Gunn
Por enviar para o analisador, você quer dizer Single.Parse()ou Single.TryParse?
mindriot
1

Você está lidando com uma string - string é um IEumerable<char>, então você pode usar LINQ:

var input = "joe ($3,004.50)";
var result = String.Join("", input.Where(c => Char.IsDigit(c) || c == '.'));

Console.WriteLine(result);   // 3004.50
wb
fonte