Localizando o número de vezes que um número específico em um arquivo em que o intervalo também foi especificado

4

Eu tenho um arquivo com números separados por , (vírgula). Entre ele também contém um intervalo numérico como 300-400 . Digamos, por exemplo, eu tenho um arquivo de texto, ou seja, testme.txt , que se parece com,

200,300,234,340-350,400,360,333-339
409-420
4444-31231231
348

Eu quero descobrir se o número 348 está presente ou não. 348 está presente em 2 lugares:

  • 340-350
  • Na última linha.

Como encontrar? Eu tentei usar regex em sed, awk, mas não consigo escrever o script completamente para capturar o intervalo de numeração. Existe alguma outra maneira de encontrá-lo?

ATUALIZAÇÃO: Encontrou 1 solução de força bruta & está funcionando apenas para alcance.

count=0;
num1=348;
for i in 'sed 's/\([0-9]\+\-[0-9]\+\)/:&:/g' testme.txt  | 
    awk -F: '{ for(i=1; i<=NF; i++) if($i ~/[0-9]+-[0-9]+/){print $i} }'';      
do 
    lh='echo $i | awk -F\- '{print $1}''; 
    rh='echo $i | awk -F\- '{print $2}'';  
    if [ $lh -le $num1 -a $rh -ge $num1 ]; 
    then  
        count='expr $count + 1'; 
    fi; 
done
echo $count;
    
por Tingrammer 21.07.2014 / 16:52

6 respostas

4

Uma solução GNU awk que trata , ou \n como um separador de registro e - como um separador de campo. Uma verificação de igualdade ou uma verificação de intervalo é aplicada dependendo do número de campos

awk -v num=348 -v RS=',|\n' -F'-' 'NF == 2 && $1 <= num && $2 >= num{c++};
           NF == 1 && $0 == num{c++};
           END{print c+0}' file
2
    
por 21.07.2014 / 17:20
3

Se você puder usar perl :

$ perl -F',' -anle '
for (@F) {
    ($l,$h) = split "-";                
    $count++ if $l == 348 || ($l < 348 and $h >= 348);
}
END {print $count}
' file
2
    
por 21.07.2014 / 17:18
2

Esta resposta fornecerá os campos que contêm o número especificado, não apenas as linhas , se você estiver após esse nível de detalhe (e se os intervalos em seus dados pode conter sobreposições):

awk -v num=348 -F, '{
  for (i=1; i<=NF; i++) {
    if ($i == num || (split($i, a, /-/) == 2 && (a[1] <= num && num <= a[2]))) {
      print $i
    }
  }
}' <<END
200,300,234,340-350,400,360,333-339
409-420
4444-31231231
348
1-400,100-1000
END
340-350
348
1-400
100-1000

Para risos, jogado no golfe:

awk -F, '{for(i=1;i<=NF;i++)if($i==n||(split($i,a,/-/)==2&&a[1]<=n&&n<=a[2]))print $i}' n=348 file
    
por 21.07.2014 / 18:06
0

Possível método para abordar o problema (já que tenho certeza de que muitas maneiras de fazer isso) é simplificar as verificações do número.

Use instruções if aninhadas para percorrer a lógica, naturalmente dividindo os 'valores' para verificar com base em um delimitador de vírgula.

Se o valor tiver um "-", para a verificação, divida os dois números em "-". Então é uma simples questão de verificar se o número que você está verificando é maior ou igual ao primeiro número E menor ou igual ao segundo número. Isso indicará que está no intervalo.

Para valores sem um "-", é uma simples verificação para ver se é igual.

Talvez não seja uma abordagem elegante, mas funcionaria (pareceu-me que você estava procurando o método para chegar às comparações e não para o roteiro pronto, então espero que o acima forneça a você esse brainstorming).

    
por 21.07.2014 / 17:09
0

Este exemplo usa correspondência de função.

%pr_e%

    
por 21.07.2014 / 21:03
0

Assumindo que sua entrada é bem formada, arquivo com lista e número como parâmetro, isso deve funcionar em PHP:

<?php
$count = 0;
foreach(explode("\n",file_get_contents($argv[1])) as $line)
foreach(explode(",",$line) as $cols)
{
    $data = split(',',$cols);
    if(((count($data)>0)&&($data[0]==$argv[2])) ||
        (count($data)>1)&&(($data[0]-$argv[2])*($data[1]-$argv[2]) < 0))
        count++;
}
echo $count;

coloque o código em um arquivo script.php e chame-o do bash assim:

php script.php testme.txt 348
    
por 22.07.2014 / 00:27