Eu tenho uma única string que contém os parâmetros da linha de comando a serem passados para outro executável e preciso extrair a string [] que contém os parâmetros individuais da mesma forma que o C # faria se os comandos tivessem sido especificados na linha de comando. A string [] será usada ao executar outro ponto de entrada de assemblies via reflexão.
Existe uma função padrão para isso? Ou existe um método preferido (regex?) Para dividir os parâmetros corretamente? Ele deve lidar com strings delimitadas por '"' que podem conter espaços corretamente, então não posso simplesmente dividir em ''.
String de exemplo:
string parameterString = @"/src:""C:\tmp\Some Folder\Sub Folder"" /users:""[email protected]"" tasks:""SomeTask,Some Other Task"" -someParam foo";
Resultado de exemplo:
string[] parameterArray = new string[] {
@"/src:C:\tmp\Some Folder\Sub Folder",
@"/users:[email protected]",
@"tasks:SomeTask,Some Other Task",
@"-someParam",
@"foo"
};
Não preciso de uma biblioteca de análise de linha de comando, apenas uma forma de obter o String [] que deve ser gerado.
Atualização : tive que alterar o resultado esperado para corresponder ao que é realmente gerado pelo C # (removidos os extras "nas strings divididas)
fonte
Respostas:
Além da boa e pura solução gerenciada por Earwicker , pode valer a pena mencionar, para fins de completude, que o Windows também fornece a
CommandLineToArgvW
função para quebrar uma string em uma série de strings:Um exemplo de como chamar esta API a partir do C # e descompactar a matriz de string resultante em código gerenciado pode ser encontrado em “ Convertendo String de Linha de Comando em Args [] usando CommandLineToArgvW () API .” Abaixo está uma versão um pouco mais simples do mesmo código:
fonte
CommandLineToArgs("foo.exe " + commandLine).Skip(1).ToArray();
Me irrita que não haja função para dividir uma string com base em uma função que examina cada caractere. Se houvesse, você poderia escrever assim:
Apesar de ter escrito isso, por que não escrever os métodos de extensão necessários. Ok, você me convenceu ...
Em primeiro lugar, minha própria versão de Split que assume uma função que tem que decidir se o caractere especificado deve dividir a string:
Pode render algumas strings vazias dependendo da situação, mas talvez essa informação seja útil em outros casos, então eu não removo as entradas vazias nesta função.
Em segundo lugar (e de forma mais prática), um pequeno auxiliar que irá cortar um par de aspas correspondentes do início e do fim de uma string. É mais complicado do que o método Trim padrão - ele cortará apenas um caractere de cada extremidade e não apenas de uma extremidade:
E suponho que você queira alguns testes também. Bem, tudo bem então. Mas isso deve ser absolutamente a última coisa! Primeiro, uma função auxiliar que compara o resultado da divisão com o conteúdo esperado da matriz:
Então posso escrever testes como este:
Este é o teste para seus requisitos:
Observe que a implementação tem o recurso extra de remover as aspas em torno de um argumento, se isso fizer sentido (graças à função TrimMatchingQuotes). Eu acredito que isso faz parte da interpretação normal da linha de comando.
fonte
char.IsWhiteSpace
vez de== ' '
O analisador de linha de comando do Windows se comporta exatamente como você diz, dividido no espaço, a menos que haja uma citação não fechada antes dele. Eu recomendaria escrever o analisador você mesmo. Algo assim talvez:
fonte
Peguei a resposta de Jeffrey L. Whitledge e a aprimorei um pouco.
Agora ele suporta aspas simples e duplas. Você pode usar aspas nos próprios parâmetros usando outras aspas digitadas.
Também remove as aspas dos argumentos, uma vez que não contribuem para as informações do argumento.
fonte
A solução bem gerenciada por Earwicker falhou em lidar com argumentos como este:
Ele retornou 3 elementos:
Portanto, aqui está uma correção para suportar a "citação de escape \" "citada":
Testado com 2 casos adicionais:
Também observou que a resposta aceita por Atif Aziz que usa CommandLineToArgvW também falhou. Ele retornou 4 elementos:
Espero que isso ajude alguém que esteja procurando por essa solução no futuro
fonte
bla.exe aAAA"b\"ASDS\"c"dSADSD
que resulta emaAAAb"ASDS"cdSADSD
onde esta solução será exibidaaAAA"b"ASDS"c"dSADSD
. Eu posso considerar mudar oTrimMatchingQuotes
para umRegex("(?<!\\\\)\\\"")
e usá-lo assim .Environment.GetCommandLineArgs ()
fonte
Eu gosto de iteradores e hoje em dia o LINQ torna-se
IEnumerable<String>
tão facilmente utilizável como arrays de string, então minha opinião seguindo o espírito da resposta de Jeffrey L Whitledge é (como um método de extensão parastring
):fonte
Em sua pergunta, você pediu um regex, e eu sou um grande fã e usuário deles, então quando precisei dividir o mesmo argumento que você, escrevi meu próprio regex após pesquisar no Google e não encontrar uma solução simples. Gosto de soluções curtas, então fiz uma e aqui está:
Ele lida com espaços em branco e aspas entre aspas e converte "" em "entre aspas. Sinta-se à vontade para usar o código!
fonte
Oh, que diabo. É tudo ... Eugh. Mas isso é oficial legítimo. Da Microsoft em C # para .NET Core, talvez apenas Windows, talvez multiplataforma, mas licenciado pelo MIT.
Selecione petiscos, declarações de métodos e comentários notáveis;
-
-
Este é o código transferido para o .NET Core a partir do .NET Framework a partir do que presumo ser a biblioteca C MSVC ou
CommandLineToArgvW
.Aqui está minha tentativa indiferente de lidar com algumas das travessuras com expressões regulares e ignorar o argumento zero bit. É um pouco mágico.
Testei bastante na saída gerada maluca. Sua saída corresponde a uma boa porcentagem do que os macacos digitaram e executaram
CommandLineToArgvW
.fonte
Este artigo do The Code Project é o que eu usei no passado. É um bom código, mas pode funcionar.
Este artigo do MSDN é a única coisa que pude encontrar que explica como o C # analisa argumentos de linha de comando.
fonte
Uma solução puramente gerenciada pode ser útil. Há muitos comentários de "problema" para a função WINAPI e ela não está disponível em outras plataformas. Aqui está meu código que tem um comportamento bem definido (que você pode alterar se quiser).
Ele deve fazer o mesmo que o .NET / Windows faz ao fornecer esse
string[] args
parâmetro, e eu comparei com uma série de valores "interessantes".Esta é uma implementação clássica de máquina de estado que pega cada caractere da string de entrada e o interpreta para o estado atual, produzindo saída e um novo estado. O estado é definido nas variáveis
escape
,inQuote
,hadQuote
eprevCh
, a saída e é recolhido emcurrentArg
eargs
.Algumas das especialidades que descobri por meio de experimentos em um prompt de comando real (Windows 7):
\\
produz\
,\"
produz"
,""
dentro de uma faixa citada, produz"
.O
^
personagem também parece mágico: sempre desaparece quando não é duplicado. Caso contrário, não tem efeito em uma linha de comando real. Minha implementação não suporta isso, pois não encontrei um padrão neste comportamento. Talvez alguém saiba mais sobre isso.Algo que não se encaixa nesse padrão é o seguinte comando:
O
cmd
comando parece pegar as aspas externas e pegar o resto literalmente. Deve haver algum molho mágico especial nisso.Não fiz benchmarks em meu método, mas considere-o razoavelmente rápido. Ele não usa
Regex
e não faz nenhuma concatenação de string, mas em vez disso usa umStringBuilder
para coletar os caracteres para um argumento e colocá-los em uma lista.fonte
Usar:
Baseado na resposta do Vapor in the Alley , este também suporta ^ escapes.
Exemplos:
Ele também suporta vários espaços (quebra os argumentos apenas uma vez por bloco de espaços).
fonte
Atualmente, este é o código que tenho:
Não funciona com aspas escapadas, mas funciona para os casos que encontrei até agora.
fonte
Esta é uma resposta ao código de Anton, que não funciona com aspas de escape. Eu modifiquei 3 lugares.
fonte
Eu não acho que existem aspas simples ou aspas ^ para aplicativos C #. A seguinte função está funcionando bem para mim:
fonte
Você pode dar uma olhada no código que postei ontem:
[C #] Strings de caminho e argumentos
Ele divide um nome de arquivo + argumentos em string []. Caminhos curtos, variáveis de ambiente e extensões de arquivo ausentes são tratados.
(Inicialmente era para UninstallString no Registro.)
fonte
Experimente este código:
Está escrito em português.
fonte
posicao_ponteiro += ((fim - posicao_ponteiro)+1);
.Aqui está uma linha que faz o trabalho (veja a linha que faz todo o trabalho dentro do método BurstCmdLineArgs (...)).
Não é o que eu chamaria de linha de código mais legível, mas você pode separá-la para fins de legibilidade. É simples propositalmente e não funciona bem para todos os casos de argumento (como argumentos de nome de arquivo que contêm o delimitador de caractere de string dividido).
Esta solução funcionou bem nas minhas soluções que a utilizam. Como eu disse, ele executa o trabalho sem um ninho de rato de código para lidar com todos os formatos de argumento n-fatoriais possíveis.
fonte
Não consegui encontrar nada de que gostei aqui. Eu odeio bagunçar a pilha com magia de rendimento para uma linha de comando pequena (se fosse um fluxo de um terabyte, seria outra história).
Aqui está minha opinião, ele suporta escapes de aspas com aspas duplas como estes:
resultado:
fonte
Implementei a máquina de estado para ter os mesmos resultados do analisador como se args fosse passado para o aplicativo .NET e processado no
static void Main(string[] args)
método.fonte
Aqui está a solução que trata os espaços (espaços simples ou múltiplos) como separadores de parâmetros de linha de comando e retorna os argumentos reais da linha de comando:
fonte
Não tenho certeza se entendi você, mas será que o problema do caractere usado como divisor também se encontra dentro do texto? (Exceto que é escapado com duplo "?)
Nesse caso, eu criaria um
for
loop e substituiria todas as instâncias onde <"> está presente por <|> (ou outro caractere" seguro ", mas certifique-se de que ele apenas substitua <">, e não <"">Depois de iterar a string, eu faria como postado anteriormente, dividir a string, mas agora no caractere <|>.
fonte
Sim, o objeto string tem uma função interna chamada
Split()
que usa um único parâmetro especificando o caractere a ser procurado como um delimitador e retorna uma matriz de strings (string []) com os valores individuais nele.fonte