Preciso pesquisar uma string e substituir todas as ocorrências de %FirstName%
e %PolicyAmount%
com um valor extraído de um banco de dados. O problema é que a capitalização do Nome varia. Isso me impede de usar o String.Replace()
método Eu vi páginas da web sobre o assunto que sugerem
Regex.Replace(strInput, strToken, strReplaceWith, RegexOptions.IgnoreCase);
No entanto, por algum motivo, quando eu tentar substituir %PolicyAmount%
com $0
, a substituição não ocorre. Suponho que isso tenha algo a ver com o cifrão sendo um caractere reservado na regex.
Existe outro método que eu possa usar que não envolva a limpeza da entrada para lidar com caracteres especiais de expressão regular?
Respostas:
Do MSDN
$ 0 - "Substitui a última substring correspondente ao número do número do grupo (decimal)."
No .NET, o grupo 0 de expressões regulares é sempre a correspondência inteira. Para um $ literal, você precisa
fonte
Parece que
string.Replace
deve ter uma sobrecarga que requer umStringComparison
argumento. Como não, você pode tentar algo como isto:fonte
ReplaceString
paraReplace
.oldValue == newValue == ""
.ReplaceString("œ", "oe", "", StringComparison.InvariantCulture)
jogaArgumentOutOfRangeException
.Um tipo de grupo confuso de respostas, em parte porque o título da pergunta é realmente muito maior do que a pergunta específica que está sendo feita. Depois de ler, não tenho certeza se alguma resposta está a algumas edições de assimilar todas as coisas boas aqui, então imaginei que tentaria resumir.
Aqui está um método de extensão que eu acho que evita as armadilhas mencionadas aqui e fornece a solução mais amplamente aplicável.
Assim...
"œ".ReplaceCaseInsensitiveFind("oe", "")
, embora ele pode ter tido um comportamento ligeiramente diferente em mente.Infelizmente, o comentário do @HA de que você tem
Escape
todos os três não está correto . O valor inicial enewValue
não precisa ser.Nota: você precisa, no entanto, escapar
$
s no novo valor que está inserindo se eles fizerem parte do que pareceria ser um marcador de "valor capturado" . Assim, os três cifrões no Regex.Replace dentro do Regex.Replace [sic]. Sem isso, algo assim quebra ..."This is HIS fork, hIs spoon, hissssssss knife.".ReplaceCaseInsensitiveFind("his", @"he$0r")
Aqui está o erro:
Para dizer a você, sei que as pessoas que se sentem confortáveis com o Regex sentem que seu uso evita erros, mas muitas vezes ainda pareço de byte farejando seqüências de caracteres (mas só depois de ler Spolsky nas codificações ) para ter certeza absoluta de que está conseguindo o que quer. destinado a casos de uso importantes. Lembra-me de Crockford em " um pouco expressões regulares inseguras ". Com muita freqüência, escrevemos regexps que permitem o que queremos (se tivermos sorte), mas involuntariamente permitimos mais entradas (por exemplo, é
$10
realmente uma cadeia de "valor de captura" válida no meu novo regexp newValue, acima?) Porque não fomos atenciosos o suficiente . Ambos os métodos têm valor e encorajam diferentes tipos de erros não intencionais. Geralmente é fácil subestimar a complexidade.Essa
$
fuga estranha (e queRegex.Escape
não escapou dos padrões de valores capturados$0
como eu esperaria em valores de substituição) me deixou louca por um tempo. A programação é difícil (c) 1842fonte
Aqui está um método de extensão. Não sei onde o encontrei.
fonte
Parece que o método mais fácil é simplesmente usar o método Replace que acompanha o .NET e existe desde o .NET 1.0:
Para usar esse método, você deve adicionar uma Referência ao Microsoft.VisualBasic em conjunto. Este assembly é uma parte padrão do tempo de execução .Net, não é um download extra ou está marcado como obsoleto.
fonte
C. Dragon 76
funcionou como esperado.fonte
Inspirado pela resposta de cfeduke, criei esta função que usa IndexOf para encontrar o valor antigo na string e depois o substitui pelo novo valor. Eu usei isso em um script SSIS processando milhões de linhas, e o método regex era muito mais lento que isso.
fonte
Expandindo a resposta popular de C. Dragon 76 , transformando seu código em uma extensão que sobrecarrega o
Replace
método padrão .fonte
Com base na resposta de Jeff Reddy, com algumas otimizações e validações:
fonte
uma versão semelhante à C. Dragon's, mas se você precisar apenas de uma única substituição:
fonte
Aqui está outra opção para executar substituições de Regex, pois poucas pessoas parecem perceber que as correspondências contêm o local dentro da cadeia:
fonte
fonte
O método de expressão regular deve funcionar. No entanto, o que você também pode fazer é minúscula a sequência do banco de dados, minúscula a% de variáveis% que você possui e, em seguida, localize as posições e comprimentos na sequência minúscula do banco de dados. Lembre-se, as posições em uma corda não mudam apenas porque é mais baixa.
Em seguida, usando um loop que é inverso (é mais fácil, se você não tiver, você terá que manter uma contagem contínua de onde os pontos posteriores se deslocam) remova da sua seqüência de caracteres não inferior do banco de dados as variáveis%% por sua posição e comprimento e insira os valores de substituição.
fonte
(Já que todo mundo está tentando fazer isso). Aqui está minha versão (com verificações nulas e escape correto de entrada e substituição) ** Inspirada na Internet e em outras versões:
Uso:
fonte
Deixe-me fazer o meu caso e então você pode me rasgar em pedaços, se quiser.
Regex não é a resposta para esse problema - muito lento e com fome de memória, relativamente falando.
StringBuilder é muito melhor que manipular string.
Como esse será um método de extensão para complementar
string.Replace
, acredito que é importante combinar como isso funciona - portanto, lançar exceções para os mesmos problemas de argumento é importante, assim como retornar a string original se uma substituição não tiver sido feita.Acredito que ter um parâmetro StringComparison não é uma boa ideia. Eu tentei, mas o caso de teste mencionado originalmente por michael-liu mostrou um problema: -
Enquanto IndexOf corresponderá, há uma incompatibilidade entre o comprimento da correspondência na cadeia de origem (1) e no oldValue.Length (2). Isso se manifestou causando IndexOutOfRange em algumas outras soluções quando oldValue.Length foi adicionado à posição de correspondência atual e não consegui encontrar uma maneira de contornar isso. O Regex falha em corresponder ao caso, então tomei a solução pragmática de usar apenas
StringComparison.OrdinalIgnoreCase
para a minha solução.Meu código é semelhante a outras respostas, mas minha opinião é que procuro uma correspondência antes de me dar ao trabalho de criar a
StringBuilder
. Se nenhum for encontrado, uma alocação potencialmente grande será evitada. O código então se torna umdo{...}while
e não umwhile{...}
Fiz alguns testes extensivos com outras respostas e isso saiu um pouco mais rápido e usou um pouco menos de memória.
fonte