Dada a sequência "ThisStringHasNoSpacesButItDoesHaveCapitals", qual é a melhor maneira de adicionar espaços antes das letras maiúsculas. Portanto, a sequência final seria "Esta sequência não possui espaços, mas possui letras maiúsculas"
Aqui está minha tentativa com um RegEx
System.Text.RegularExpressions.Regex.Replace(value, "[A-Z]", " $0")
Respostas:
As expressões regulares funcionarão bem (eu até votei na resposta de Martin Browns), mas são caras (e pessoalmente acho qualquer padrão mais longo que alguns caracteres proibitivamente obtusos)
Esta função
Será feito 100.000 vezes em 2.968.750 ticks, o regex terá 25.000.000 ticks (e isso é com o regex compilado).
É melhor, para um determinado valor de melhor (ou seja, mais rápido), no entanto, é mais código para manter. "Melhor" geralmente é o comprometimento de requisitos concorrentes.
Espero que isto ajude :)
Atualização
Já faz um bom tempo desde que olhei para isso, e acabei de perceber que os tempos não foram atualizados desde que o código mudou (apenas mudou um pouco).
Em uma sequência com 'Abbbbbbbbb' repetida 100 vezes (ou seja, 1.000 bytes), uma execução de 100.000 conversões assume a função codificada manualmente 4.517.177 ticks, e o Regex abaixo leva 59.435.719 fazendo a função codificada manualmente ser executada em 7,6% do tempo necessário. Regex.
Atualização 2 Levará em consideração os acrônimos? Será agora! A lógica da declaração if é bastante obscura, como você pode ver expandindo-a para isso ...
... não ajuda em nada!
Aqui está o método simples original que não se preocupa com acrônimos
fonte
Sua solução tem um problema, pois coloca um espaço antes da primeira letra T para que você obtenha
Para contornar isso, procure também a letra minúscula que a precede e insira o espaço no meio:
Editar 1:
Se você usá-
@"(\p{Ll})(\p{Lu})"
lo, também selecionará caracteres acentuados.Edição 2:
Se suas seqüências de caracteres podem conter siglas, convém usar isso:
Assim, "DriveIsSCSICompatible" se torna "Drive Is SCSI Compatible"
fonte
"([^A-Z\\s])([A-Z])"
, mesmo com siglas?Não testou o desempenho, mas aqui em uma linha com linq:
fonte
Sei que é antigo, mas é uma extensão que uso quando preciso fazer isso:
Isso permitirá que você use
MyCasedString.ToSentence()
fonte
TrimStart(' ')
ele removerá o espaço principal.SelectMany
que inclui um índice, dessa forma evita a primeira letra e o potencial desnecessário de sobrecarga de uma chamada adicional paraTrimStart(' ')
. Roubar.Bem-vindo ao Unicode
Todas essas soluções estão essencialmente erradas no texto moderno. Você precisa usar algo que entenda o caso. Como Bob pediu outros idiomas, darei um par para Perl.
Eu forneço quatro soluções, variando do pior ao melhor. Somente o melhor tem sempre razão. Os outros têm problemas. Aqui está um teste para mostrar o que funciona e o que não funciona e onde. Usei sublinhados para que você possa ver onde os espaços foram colocados e marquei como errado qualquer coisa que esteja, bem, errada.
BTW, quase todo mundo aqui selecionou o primeiro caminho, o marcado "Pior". Alguns selecionaram a segunda maneira, marcada com "OK". Mas ninguém antes de mim mostrou como fazer a abordagem "Melhor" ou "Melhor".
Aqui está o programa de teste com seus quatro métodos:
Quando você conseguir a mesma pontuação como "Melhor" neste conjunto de dados, saberá que fez isso corretamente. Até então, você não tinha. Ninguém aqui se saiu melhor do que "Ok", e a maioria fez "Pior". Estou ansioso para ver alguém postar o código correto.
Percebo que o código de destaque do StackOverflow é miseravelmente estúpido novamente. Eles estão fazendo o mesmo velho e coxo que (a maioria, mas não todos), do restante das abordagens pobres mencionadas aqui. Não é muito tempo para colocar o ASCII em repouso? Não faz mais sentido, e fingir que é tudo que você tem é simplesmente errado. Isso cria um código incorreto.
fonte
Decidi criar um método de extensão simples, baseado no código do Binary Worrier, que manipulará os acrônimos corretamente e é repetível (não manipulará palavras espaçadas). Aqui está o meu resultado.
Aqui estão os casos de teste de unidade em que essa função passa. Adicionei a maioria dos casos sugeridos por tchrist a esta lista. Os três dos quais não passa (dois são apenas algarismos romanos) são comentados:
fonte
Preocupante binário, usei o código sugerido e é bastante bom, tenho apenas uma pequena adição a ele:
Eu adicionei uma condição
!char.IsUpper(text[i - 1])
. Isso corrigiu um bug que faria com que algo como 'AverageNOX' fosse transformado em 'Average NOX', o que está obviamente errado, pois deveria ser 'Average NOX'.Infelizmente, ainda existe o erro de que, se você tiver o texto 'FromAStart', obterá o 'From AStart'.
Alguma idéia de consertar isso?
fonte
if (char.IsUpper(text[i]) && !(char.IsUpper(text[i - 1]) && char.IsUpper(text[i + 1])))
Resultado do teste: "Desde o início", "Desde o início", "Desde o início", mas você precisai < text.Length - 1
na condição do loop for para ignorar o último caractere e evitar a exceção fora do intervalo.Aqui está o meu:
fonte
<pre><code>code</code></pre>
bloco em vez da sintaxe Markdown. Não há necessidade de voto negativo (se fosse você).Certifique-se de que você não está colocando os espaços no início da cadeia, mas você está colocando-os entre as capitais consecutivos. Algumas das respostas aqui não tratam de um ou de ambos os pontos. Existem outras maneiras além da regex, mas se você preferir usar isso, tente o seguinte:
O
\B
é negado\b
, portanto representa um limite que não é da palavra. Isso significa que o padrão corresponde a "Y" emXYzabc
, mas não emYzabc
ouX Yzabc
. Como um pequeno bônus, você pode usar isso em uma string com espaços e ela não os duplicará.fonte
Este Regex coloca um caractere de espaço na frente de cada letra maiúscula:
Observe o espaço em frente se "$ 1 $ 2", é isso que fará com que seja feito.
Este é o resultado:
fonte
"([A-Z0-9])([a-z]*)"
O que você tem funciona perfeitamente. Lembre-se de reatribuir
value
ao valor de retorno dessa função.fonte
Aqui está como você pode fazer isso no SQL
fonte
Inspirado em @MartinBrown, Duas Linhas de Regex Simples, que resolverão seu nome, incluindo Acyrônimos em qualquer lugar da string.
fonte
fonte
fonte
Em Ruby, via Regexp:
fonte
Tomei Kevin Strikers excelente solução e convertido para VB. Desde que eu estou bloqueado no .NET 3.5, eu também tive que escrever IsNullOrWhiteSpace. Isso passa em todos os seus testes.
fonte
A questão é um pouco antiga, mas hoje em dia existe uma boa biblioteca no Nuget que faz exatamente isso, além de muitas outras conversões em texto legível por humanos.
Confira o Humanizer no GitHub ou Nuget.
Exemplo
fonte
Parece uma boa oportunidade para
Aggregate
. Isso foi projetado para ser legível, não necessariamente especialmente rápido.fonte
Além da resposta de Martin Brown, também tive um problema com os números. Por exemplo: "Local2" ou "Jan22" deve ser "Local 2" e "22 de janeiro", respectivamente.
Aqui está minha expressão regular para fazer isso, usando a resposta de Martin Brown:
Aqui estão alguns ótimos sites para descobrir o que cada parte significa também:
Analisador de expressão regular baseado em Java (mas funciona para a maioria dos regex .net)
Analisador Baseado em Script de Ação
A regex acima não funcionará no site do script de ação, a menos que você substitua todos por
\p{Ll}
with[a-z]
, the\p{Lu}
with[A-Z]
e\p{Nd}
with[0-9]
.fonte
Aqui está minha solução, com base na sugestão e construção dos Binários Preocupantes nos comentários de Richard Priddys, mas também levando em consideração que pode haver espaço em branco na cadeia fornecida, para que ele não adicione espaço em branco ao lado do espaço em branco existente.
fonte
Para quem procura uma função C ++ que responda a essa mesma pergunta, você pode usar o seguinte. Isso é modelado após a resposta dada pelo @Binary Worrier. Este método apenas preserva acrônimos automaticamente.
As strings de teste que usei para esta função e os resultados são:
fonte
Uma solução C # para uma sequência de entrada que consiste apenas em caracteres ASCII. O regex incorpora lookbehind negativo para ignorar uma letra maiúscula (maiúscula) que aparece no início da string. Usa Regex.Replace () para retornar a sequência desejada.
Veja também a demonstração de regex101.com .
Saída esperada:
Atualização: Aqui está uma variação que também manipula acrônimos (sequências de letras maiúsculas).
Veja também a demo regex101.com e a ideone.com .
Saída esperada:
fonte
Aqui está uma solução mais completa que não coloca espaços na frente das palavras:
Nota: Eu usei vários Regexs (não concisos, mas ele também manipula acrônimos e palavras de uma letra)
Em :
Fora :
fonte
Todas as respostas anteriores pareciam muito complicadas.
Eu tinha uma string que tinha uma mistura de maiúsculas e _ usada, string.Replace () para criar o _, "" e usei o seguinte para adicionar um espaço nas letras maiúsculas.
fonte
Inspirado pela resposta do binário, preocupei-me com isso.
Aqui está o resultado:
Testou usando o cronômetro executando 10000000 iterações e vários comprimentos e combinações de cordas.
Em média, 50% (talvez um pouco mais) mais rápido que a resposta Binary Worrier.
fonte
fonte
Este inclui acrônimos e plurais de acrônimos e é um pouco mais rápido que a resposta aceita:
Passa nos testes:
fonte
Uma implementação com
fold
, também conhecida comoAggregate
:Além da solicitação, essa implementação salva corretamente os espaços à esquerda, à direita, à direita e os acrônimos, por exemplo,
fonte
Uma maneira simples de adicionar espaços após letras minúsculas, maiúsculas ou dígitos.
fonte