ant: extrair valor de um par de valores-chave em uma string de consulta de URL

4

Estou tentando usar sed para extrair a parte do valor de um dos muitos pares de valores-chave na string de consulta de uma URL

É isso que estou tentando:

echo 'http://www.youtube.com/watch?v=abc&g=xyz' | sed 's@^https?://(www.)?youtube.com/(watch\?)?.*?v(=|/)([a-zA-Z0-9\-_]*)(&.*)?$@$4@'

mas sempre exibe o URL de entrada como está.

O que estou fazendo de errado?

Atualização 1

Para esclarecer algumas questões:

  1. O regex é mais complicado do que tem que ser porque também estou tentando verificar a validade da entrada e gerar a saída apenas se a entrada for válida. Então, um jogo mais estrito.
  2. A saída desejada é o valor da chave 'v' na string de consulta.
  3. Não conseguimos encontrar a versão de sed que estou usando, mas é a que vem com o Mac OS X (10.7.5).
  4. Na minha versão de sed $ 1, $ 2 etc. parecem ser as correspondências, \ 1, \ 2 etc. dão o erro: sed: 1: "s@^https?://(www.)?yout ...": not defined in the RE Não está correto! como descobri mais tarde. Desculpas por causar a confusão.

Atualização 2

Atualizou o sed RE para torná-lo mais específico com base na sugestão de @slhck abaixo, mas o problema permanece como antes.

Atualização 3

Com base na página man desta versão de sed , parece que esta é uma versão com sabor BSD.

    
por markvgti 04.06.2013 / 14:48

5 respostas

11

Ainda mais simples, se você quiser apenas o abc :

 echo 'http://www.youtube.com/watch?v=abc&g=xyz' | awk -F'[=&]' '{print $2}'

Se você quiser o xyz :

echo 'http://www.youtube.com/watch?v=abc&g=xyz' | awk -F'[=&]' '{print $4}'

EXPLICAÇÃO:

  • awk : é uma linguagem de script que processa automaticamente os arquivos de entrada linha por linha, dividindo cada linha em campos. Portanto, quando você processa um arquivo com awk , para cada linha, o primeiro campo é $1 , o segundo $2 etc até $N . Por padrão, awk usa espaços em branco como o separador de campo.

  • -F'[=&]' : -F é usado para alterar o delimitador de campo de espaços para outra coisa. Nesse caso, estou dando uma classe de caracteres. Colchetes ( [ ] ) são usados por muitos idiomas para denotar grupos de caracteres. Portanto, especificamente, -F'[=&]' significa que awk deve usar tanto & quanto = como delimitadores de campo.

  • Portanto, considerando a string de entrada da sua pergunta, usando & e = como delimitadores, awk lerá os seguintes campos:

    http://www.youtube.com/watch?v=abc&g=xyz
    |----------- $1 -------------| --- - ---      
                                    |  |  |
                                    |  |  ̣----- $4
                                    |  -------- $3
                                    ----------- $2
    

    Então, tudo que você precisa fazer é imprimir o que você quiser {print $4} .

Você disse que também quer verificar se a string é uma URL válida do youtube, você não pode fazer isso com sed , pois se ela não corresponder à regex que você der, ela simplesmente imprimirá a linha inteira. Você pode usar uma ferramenta como Perl para imprimir apenas se a regex corresponder:

echo 'http://www.youtube.com/watch?v=abc&g=xyz' | 
  perl -ne 's/http.*www.youtube.com\/watch\?v=(.+?)&.+/$1/ && print'

Por fim, para simplesmente imprimir abc , você pode usar a ferramenta padrão do UNIX cut :

echo 'http://www.youtube.com/watch?v=abc&g=xyz' | 
  cut -d '=' -f 2 | cut -d '&' -f 1
    
por 04.06.2013 / 15:35
2

se você precisar de "xyz" tente isto (GNU sed):

echo 'http://www.youtube.com/watch?v=abc&g=xyz' | sed 's/.*=\([[:alnum:]]*\).*//'
    
por 04.06.2013 / 15:24
2

Experimentar sed com base nas respostas dadas por @Endoro e @slhck me levou à resposta final (a que eu queria). Isso é o que funciona para mim com a versão de sed no Mac OS X (10.7.5):

echo 'http://www.youtube.com/watch?v=dnCkNz_xrpg' | sed -E 's@https?://(www\.)?youtube.com/(watch\?).*v=([-_a-zA-Z0-9]*).*@@'

Explicação:

  1. -E é fazer com que sed use o RE estendido. Em outras versões do sed -r pode ser a opção equivalente.
  2. O ER, aparentemente mais complicado do que necessário, é também verificar se esse é um link válido do YouTube. Modifique as partes iniciais deste RE conforme necessário (por exemplo, https?://(www\.)?example.com/(.*\?).*key=([^&]*).* )
  3. O corresponde à terceira expressão entre parênteses e imprime como resposta / correspondência (que é o que eu quero).
  4. Usando '@@@' ao invés do usual 's ///' para que eu não tenha que escapar das muitas barras ( \ ) em uma URL.

Espero que isso ajude os outros também como eu fui ajudado.

    
por 05.06.2013 / 06:39
1

Se você realmente quer apenas o ID do vídeo - então, qualquer coisa entre v= e o próximo & - é só usar:

sed -r 's/.*v=([[:alnum:]]*).*//'

Veja o que há de errado com seu comando:

  • O -r é necessário para usar expressões regulares estendidas. Se você deixar isso de lado, sed interpreta os parênteses literalmente, então não haverá grupos de correspondência. Com BSD sed , use a opção -E .

  • Você usa $1 para se referir a correspondências, mas deve usar . $1 é na verdade um argumento shell passado para o script atual, por exemplo.

  • Você deve usar uma classe de caractere como [[:alnum:]] (ou [a-zA-Z0-9_] dependendo de como os IDs estão configurados) para corresponder ao valor do parâmetro, caso contrário, o próximo & também será capturado. O regex é ganancioso e apenas corresponderá a abc&g=xyz se você usar .*? , já que a quantificação lenta não é suportada em BRE / ERE, e somente em regex Perl ou outros sabores "modernos".

por 04.06.2013 / 15:14
0

Ele sempre exibe o URL porque o SED não corresponde a ele.

    echo 'http://www.youtube.com/watch?v=abc&g=xyz' | sed 's!^http://www.youtube.com/watch\?\(.*=.*\)&\(.*=.*\)!!'

Exibirá v = abc

    
por 19.09.2014 / 05:18