@TotZam - verifique as datas. Este é mais antigo que o que você vinculou.
Página
@ToolmakerSteve Costumo olhar para a qualidade das perguntas e respostas, não das datas, como dito aqui . Nesse caso, parece que cometi um erro e cliquei no errado para marcar como duplicado, pois a qualidade dessa pergunta é obviamente melhor e, portanto, sinalizei a outra pergunta.
Tot Zam
@ TotZam - ah, eu não sabia sobre essa recomendação - obrigado por apontá-la. (Embora seja confuso ver algo mais antigo relatado como duplicado de algo mais novo, nesse caso, vale a pena explicar explicitamente que você está marcando como duplicada uma pergunta MAIS ANTIGA, porque a pergunta vinculada tem respostas melhores.)
ToolmakerSteve
Respostas:
198
A maneira mais fácil de adicionar e remover intervalos em uma string é usar o StringBuilder.
var theString ="ABCDEFGHIJ";var aStringBuilder =newStringBuilder(theString);
aStringBuilder.Remove(3,2);
aStringBuilder.Insert(3,"ZX");
theString = aStringBuilder.ToString();
Uma alternativa é usar String.Substring, mas acho que o StringBuildercódigo fica mais legível.
seria melhor enrolamento que se em um método de extensão :)
balexandre
Por que você usa um StringBuilder aqui? Verifique a resposta de V4Vendetta, que é muito mais legível ...
Fortega
1
@ Fortega Remove () e Insert () criam e retornam uma nova string. A abordagem StringBuilder evita esse custo extra trabalhando em uma seção pré-alocada da memória e movendo os caracteres dentro dela.
Redcalx #
@redcalx Isso é verdade, mas um custo extra é introduzido através da introdução de um objeto StringBuilder e reduzindo a legibilidade
Fortega
2
Qual é o sentido de usar o StringBuilder aqui, se você estiver chamando Remover e Inserir da mesma maneira que V4Vendetta, mas ele está fazendo isso diretamente na cadeia? Parece código redundante.
metabuddy
186
string s ="ABCDEFGH";
s= s.Remove(3,2).Insert(3,"ZX");
Eu prefiro isso do que inicializar um novo StringBuilder (...). Obrigado!
Michael Norgren
3
Não sei por que alguém usaria stringbuilder para esta operação. Esta é uma boa resposta #
NappingRabbit 16/07/19
43
ReplaceAt (índice int, comprimento int, substituição de cadeia)
Aqui está um método de extensão que não usa StringBuilder ou Substring. Esse método também permite que a cadeia de substituição se estenda além do comprimento da cadeia de origem.
//// str - the source string//// index- the start location to replace at (0-based)//// length - the number of characters to be removed before inserting//// replace - the string that is replacing characterspublicstaticstringReplaceAt(thisstring str,int index,int length,string replace){return str.Remove(index,Math.Min(length, str.Length- index)).Insert(index, replace);}
Ao usar esta função, se você desejar que toda a cadeia de substituição substitua o máximo de caracteres possível, defina o comprimento como o comprimento da cadeia de substituição:
Eu acho que isso é mais eficiente, uma vez que a classe StringBuilder não precisa ser inicializada e uma vez que usa operações mais básicas. Por favor corrija-me se eu estiver errado. :)
Eu criei três métodos que usam os três métodos acima (string.Remove / Inserir, Stringbuilder.Remove / Inserir e resposta Substring de Daniel, e SubString foi o método mais rápido.
Isso funciona, você provavelmente não quer recolocar t.
Pierre
4
Se você se preocupa com o desempenho, o que você deseja evitar aqui são alocações. E se você estiver no .Net Core 2.1+ (ou ainda não lançado, .Net Standard 2.1), poderá usar o string.Createmétodo :
Todas as outras respostas não funcionam se a string contiver um caractere Unicode (como Emojis), porque um caractere Unicode pesa mais bytes que um caractere.
Exemplo : o emoji '🎶' convertido em bytes pesará o equivalente a 2 caracteres. Portanto, se o caractere unicode for colocado no início da sua string, o offsetparâmetro será alterado).
Com este tópico , estendo a classe StringInfo para Replace by position mantendo o algoritmo de Nick Miller para evitar que:
dotnetfiddle.net/l0dqS5 Não foi possível obter outros métodos para falhar no Unicode. Altere o violino para demonstrar seu caso de uso. Muito interessado, em resultados.
Markus
1
@MarkusHooge Tente colocar os caracteres unicode no início da sua string, como: dotnetfiddle.net/3V2K3Y . Você verá que apenas a última linha funciona bem e coloca o caractere no 4º lugar (no outro caso, o caractere unicode leva 2 caracteres de comprimento)
GGO
Você está certo, não está claro. Atualizei minha resposta para adicionar mais explicações sobre por que as outras respostas não funcionam
GGO 15/03/19
1
Eu estava procurando uma solução com os seguintes requisitos:
use apenas uma única expressão de uma linha
use apenas métodos internos do sistema (nenhum utilitário implementado personalizado)
Solução 1
A solução que melhor me convém é esta:
// replace `oldString[i]` with `c`string newString =newStringBuilder(oldString).Replace(oldString[i], c, i,1).ToString();
A outra solução que atende aos meus requisitos é usar Substringcom concatenação:
string newString = oldStr.Substring(0, i)+ c + oldString.Substring(i+1, oldString.Length);
Tudo bem também. Eu acho que não é tão eficiente quanto o primeiro em termos de desempenho (devido a concatenação desnecessária de strings). Mas a otimização prematura é a raiz de todo mal .
Deixe-me explicar minha solução.
Dada a declaração do problema de alterar uma sequência em suas duas posições específicas (“posição 4 para a posição 5”) com dois caracteres 'Z' e 'X', a solicitação é usar o índice de posição para alterar a sequência e não a sequência Substituir ( ) (pode ser devido à possibilidade de repetição de alguns caracteres na string real), eu preferiria usar uma abordagem minimalista para atingir o objetivo em vez de usar uma Substring()string Concat()ou string Remove()e Insert()abordagem. Embora todas essas soluções tenham o objetivo de atingir o mesmo objetivo, isso depende apenas da escolha pessoal e da filosofia de se estabelecer com uma abordagem minimalista.
Voltando à minha solução mencionada acima, se dermos uma olhada mais de perto stringeStringBuilder, ambos tratam internamente uma determinada sequência como uma matriz de caracteres. Se olharmos para a implementação, StringBuilderela mantém uma variável interna algo como “ internal char[] m_ChunkChars;” para capturar a sequência especificada. Agora, como essa é uma variável interna, não podemos acessar diretamente a mesma. Para o mundo externo, para poder acessar e alterar essa matriz de caracteres, os StringBuilderexpõe através da propriedade do indexador, que se parece com abaixo
[IndexerName("Chars")]publiccharthis[int index]{get{StringBuilder stringBuilder =this;do{// … some codereturn stringBuilder.m_ChunkChars[index1];// … some more code}}set{StringBuilder stringBuilder =this;do{//… some code
stringBuilder.m_ChunkChars[index1]=value;return;// …. Some more code}}}
Minha solução mencionada acima utiliza esse recurso do indexador para alterar diretamente a matriz de caracteres mantida internamente, que o IMO é eficiente e minimalista.
BTW; podemos reescrever a solução acima de forma mais elaborada, algo como abaixo
Nesse contexto, também gostaria de mencionar que, no caso string, também possui propriedade indexadora como forma de expor sua matriz de caracteres internos, mas nesse caso, ela possui apenas a propriedade Getter (e nenhum Setter), pois a string é imutável por natureza. E é por isso que precisamos usar StringBuilderpara alterar a matriz de caracteres.
E por último, mas não menos importante, esta solução é a mais adequada para esse problema específico, em que a solicitação é substituir apenas alguns caracteres por um índice de posição conhecido antecipadamente. Pode não ser o melhor ajuste quando o requisito é alterar uma sequência bastante longa, ou seja, o número de caracteres a serem alterados é grande em números.
Eu acredito que a maneira mais simples seria essa: (sem construtor de string)
string myString ="ABCDEFGHIJ";char[] replacementChars ={'Z','X'};byte j =0;for(byte i =3; i <=4; i++, j++){
myString = myString.Replace(myString[i], replacementChars[j]);}
Isso funciona porque uma variável do tipo string pode ser tratada como uma matriz de variáveis de caracteres. Você pode, por exemplo, consultar o segundo caractere de uma variável de cadeia com o nome "myString" como myString [1]
Isso funciona apenas porque no exemplo do autor stringos caracteres a serem substituídos ocorrem apenas uma vez. Se você executar isso contra, digamos, "DBCDEFGHIE"obterá "ZBCZXFGHIX", que não é o resultado desejado. Além disso, eu não concordaria que isso seja mais simples do que as outras não- StringBuildersoluções postadas há dois anos e meio.
Respostas:
A maneira mais fácil de adicionar e remover intervalos em uma string é usar o
StringBuilder
.Uma alternativa é usar
String.Substring
, mas acho que oStringBuilder
código fica mais legível.fonte
fonte
ReplaceAt (índice int, comprimento int, substituição de cadeia)
Aqui está um método de extensão que não usa StringBuilder ou Substring. Esse método também permite que a cadeia de substituição se estenda além do comprimento da cadeia de origem.
Ao usar esta função, se você desejar que toda a cadeia de substituição substitua o máximo de caracteres possível, defina o comprimento como o comprimento da cadeia de substituição:
Caso contrário, você pode especificar a quantidade de caracteres que serão removidos:
Se você especificar o comprimento como 0, essa função funcionará exatamente como a função de inserção:
Eu acho que isso é mais eficiente, uma vez que a classe StringBuilder não precisa ser inicializada e uma vez que usa operações mais básicas. Por favor corrija-me se eu estiver errado. :)
fonte
Use
String.Substring()
(detalhes aqui ) para cortar a parte esquerda, a sua substituição e a parte direita. Brinque com índices até acertar :)Algo como:
fonte
Como um método de extensão.
fonte
fonte
t
.Se você se preocupa com o desempenho, o que você deseja evitar aqui são alocações. E se você estiver no .Net Core 2.1+ (ou ainda não lançado, .Net Standard 2.1), poderá usar o
string.Create
método :Essa abordagem é mais difícil de entender do que as alternativas, mas é a única que alocará apenas um objeto por chamada: a sequência recém-criada.
fonte
Você pode tentar algo vincular isso:
fonte
Como outros já mencionaram, a
Substring()
função existe por uma razão:Também cronometrei isso contra a
StringBuilder
solução e obtive 900 tiques vs. 875. Portanto, é um pouco mais lento.fonte
"ABCDEFGHIJ"
e"ZX"
são de diferentes comprimentos.Ainda outra
fonte
Com a ajuda deste post, crio a seguinte função com verificações adicionais de comprimento
fonte
Todas as outras respostas não funcionam se a string contiver um caractere Unicode (como Emojis), porque um caractere Unicode pesa mais bytes que um caractere.
Com este tópico , estendo a classe StringInfo para Replace by position mantendo o algoritmo de Nick Miller para evitar que:
fonte
Eu estava procurando uma solução com os seguintes requisitos:
Solução 1
A solução que melhor me convém é esta:
Isso usa
StringBuilder.Replace(oldChar, newChar, position, count)
Solução 2
A outra solução que atende aos meus requisitos é usar
Substring
com concatenação:Tudo bem também. Eu acho que não é tão eficiente quanto o primeiro em termos de desempenho (devido a concatenação desnecessária de strings). Mas a otimização prematura é a raiz de todo mal .
Então escolha o que você mais gosta :)
fonte
É melhor usar o
String.substr()
.Como isso:
fonte
Deixe-me explicar minha solução.
Dada a declaração do problema de alterar uma sequência em suas duas posições específicas (“posição 4 para a posição 5”) com dois caracteres 'Z' e 'X', a solicitação é usar o índice de posição para alterar a sequência e não a sequência Substituir ( ) (pode ser devido à possibilidade de repetição de alguns caracteres na string real), eu preferiria usar uma abordagem minimalista para atingir o objetivo em vez de usar uma
Substring()
stringConcat()
ou stringRemove()
eInsert()
abordagem. Embora todas essas soluções tenham o objetivo de atingir o mesmo objetivo, isso depende apenas da escolha pessoal e da filosofia de se estabelecer com uma abordagem minimalista.Voltando à minha solução mencionada acima, se dermos uma olhada mais de perto
string
eStringBuilder
, ambos tratam internamente uma determinada sequência como uma matriz de caracteres. Se olharmos para a implementação,StringBuilder
ela mantém uma variável interna algo como “internal char[] m_ChunkChars;
” para capturar a sequência especificada. Agora, como essa é uma variável interna, não podemos acessar diretamente a mesma. Para o mundo externo, para poder acessar e alterar essa matriz de caracteres, osStringBuilder
expõe através da propriedade do indexador, que se parece com abaixoMinha solução mencionada acima utiliza esse recurso do indexador para alterar diretamente a matriz de caracteres mantida internamente, que o IMO é eficiente e minimalista.
BTW; podemos reescrever a solução acima de forma mais elaborada, algo como abaixo
Nesse contexto, também gostaria de mencionar que, no caso
string
, também possui propriedade indexadora como forma de expor sua matriz de caracteres internos, mas nesse caso, ela possui apenas a propriedade Getter (e nenhum Setter), pois a string é imutável por natureza. E é por isso que precisamos usarStringBuilder
para alterar a matriz de caracteres.E por último, mas não menos importante, esta solução é a mais adequada para esse problema específico, em que a solicitação é substituir apenas alguns caracteres por um índice de posição conhecido antecipadamente. Pode não ser o melhor ajuste quando o requisito é alterar uma sequência bastante longa, ou seja, o número de caracteres a serem alterados é grande em números.
fonte
fonte
Aqui está um método de extensão simples:
Use-o assim:
fonte
Eu acredito que a maneira mais simples seria essa: (sem construtor de string)
Isso funciona porque uma variável do tipo string pode ser tratada como uma matriz de variáveis de caracteres. Você pode, por exemplo, consultar o segundo caractere de uma variável de cadeia com o nome "myString" como myString [1]
fonte
string
os caracteres a serem substituídos ocorrem apenas uma vez. Se você executar isso contra, digamos,"DBCDEFGHIE"
obterá"ZBCZXFGHIX"
, que não é o resultado desejado. Além disso, eu não concordaria que isso seja mais simples do que as outras não-StringBuilder
soluções postadas há dois anos e meio.