A string “abcedf” pode ser combinada com a string “bafcde” em um único comando de linha?

2

Estou planejando implementar uma estrutura de indexação no meu programa. Por exemplo, se eu tiver 100 linhas na tabela, numerarei essas linhas de 1 a 100 em outra coluna anexando um _ ao final do número ( 1_,2_,3_ etc , para que cada número pode ser identificado exclusivamente).

Depois de processar as linhas, estou armazenando a saída em um arquivo.

Por exemplo, insiro a linha 1_,2_,4_,5_ em um arquivo.

se eu obtiver um valor como 5_,2_,1_,4_ ou 2_,5_,1_,4_ , não devo inserir esses valores.

Uma implementação que me vem à mente é classificar os números e compará-los. No entanto, se o total de linhas se tornar 100.000, não será uma boa solução. É possível como um comando de linha única no script perl ou awk ou sed ?

EDITAR :

Para ser mais preciso e curto, para um conjunto de valores únicos e distintos, como posso encontrar todas as combinações sem repetições?

Exemplo :

Se eu tiver 3 chaves exclusivas 1,2 and 3 , como posso encontrar todas as combinações sem a mesma combinação repetida duas vezes?

Então, para o exemplo acima, podemos encontrar uma combinação como

123

Agora, quando eu pesquisar por 213 ou 321 , ele deve me corresponder, pois já tenho a combinação 123 obtida.

    
por Ramesh 01.03.2014 / 03:20

5 respostas

4

Você poderia configurar um banco de dados SQLite e realizar seleções de SQL a partir dele, o que provavelmente seria mais limpo de implementar e o configuraria para ser mais portátil posteriormente.

Mas aqui está uma idéia aproximada. Digamos que eu tenha 2 arquivos:

$ more index.txt new_vals.txt 
::::::::::::::
index.txt
::::::::::::::
1_,2_,4_,5_
::::::::::::::
new_vals.txt
::::::::::::::
5_,2_,1_,4
2_,5_,1_,4

Com este comando, podemos corresponder:

$ for i in $(<new_vals.txt); do nums=${i//_,/}; \
        grep -oE "[${nums}_,]+" index.txt; done
1_,2_,4_,5_
1_,2_,4_,5_

Isso demonstra que podemos corresponder cada linha de new_vals.txt a uma linha existente em index.txt .

UPDATE # 1

Com base na edição do OP, o seguinte faria o que ele quiser usando uma modificação da abordagem acima.

$ for i in $(<new_vals.txt); do 
  nums=${i//_,/} 

  printf "# to check: [%s]" $i
  k=$(grep -oE "[${nums}_,]+" index.txt | grep "[[:digit:]]_$")
  printf " ==> match: [%s]\n" $k

done

Com uma versão modificada dos dados de teste:

$ more index.txt new_vals.txt 
::::::::::::::
index.txt
::::::::::::::
1_,2_,4_,5_
0_,2_,3_,9_
::::::::::::::
new_vals.txt
::::::::::::::
5_,2_,1_,4_
2_,5_,1_,4_
1_,1_,1_,1_
1_,2_,4_,4_

Agora, quando executarmos o acima (coloque dentro de um script para simplificar, parser.bash ):

$ ./parser.bash 
# to check: [5_,2_,1_,4_] ==> match: [1_,2_,4_,5_]
# to check: [2_,5_,1_,4_] ==> match: [1_,2_,4_,5_]
# to check: [1_,1_,1_,1_] ==> match: []
# to check: [1_,2_,4_,4_] ==> match: []

Como funciona

O método acima funciona explorando algumas características-chave exibidas pela natureza dos seus dados. Por exemplo. Somente as correspondências terminarão com um dígito seguido por um sublinhado. O grep "[[:digit:]]_$" seleciona apenas esses resultados.

A outra parte do script, grep -oE "[${nums}_,]+" index.txt , selecionará as linhas que contêm caracteres das strings no arquivo new_vals.txt , que correspondem às strings de index.txt .

Ajustes adicionais

Se a natureza dos dados for tal que as strings podem ser variáveis em comprimento, então o segundo grep precisará ser expandido para garantir que estamos escolhendo apenas strings de tamanho suficiente. Existem várias maneiras de fazer isso, seja expandindo o padrão ou fazendo uso de um contador, talvez usando wc ou algum outro meio, que confirmaria que as correspondências são de um certo tipo.

Expandindo assim:

k=$(grep -oE "[${nums}_,]+" index.txt | \
    grep "[[:digit:]]_,[[:digit:]]_,[[:digit:]]_,[[:digit:]]_$")

Permitiria a eliminação de sequências como esta:

$ ./parser2.bash 
# to check: [5_,2_,1_,4_] ==> match: [1_,2_,4_,5_]
# to check: [2_,5_,1_,4_] ==> match: [1_,2_,4_,5_]
# to check: [1_,1_,1_,1_] ==> match: []
# to check: [1_,2_,4_,4_] ==> match: []
# to check: [1_,2_,5_] ==> match: []
    
por 01.03.2014 / 03:40
5

Encontrar uniques é fácil com sed :

{ 
echo identical identical
echo not_so_much as_before
echo abcdef bafcde
} | sed ':u;s/\(.\)\(.*\)//;tu'

OUTPUT:

nto_much abfr

Não tenho certeza de como representá-lo corretamente em Markdown , mas a saída do comando acima é na verdade uma nova linha e o espaço único que separa as duas strings, depois as acima, depois outra nova linha e espaço.

A função t sed é um dispositivo totalmente portátil definido pelo POSIX . :

[2addr]t [label] Test.

Branch to the : command verb bearing the label if any substitutions have been made since the most recent reading of an input line or execution of a t. If label is not specified, branch to the end of the script.

Vamos ver como funciona, adicionarei um p rint no lugar certo:

{ 
echo identical identical
echo not_so_much as_before
echo abcdef bafcde
} | sed ':u;s/\(.\)\(.*\)//p;tu'

OUTPUT:

dentical identcal
entical ientcal
ntical intcal
tical itcal
ical ical
cal cal
al al
l l


nt_so_much as_befre
ntso_much asbefre
nto_much abefre
nto_much abfr
nto_much abfr
bcdef bfcde
cdef fcde
def fde
ef fe
f f

Você pode ver que há uma quantidade diferente de espaço vazio entre os três diferentes t ests. Este é um resultado da ordem em que sed nega os caracteres, o que significa que whitespaces também são negados, desde que haja um número par deles.

O comando:

sed ':u;s/\(.\)\(.*\)//;tu'

s/ elege o primeiro \(. character \) em uma linha que pode ser selecionada duas vezes, e \(. all *\) caracteres entre os dois. Então, / substitui / a seleção inteira com somente a seleção entre eles. : Enxaguar, repea t .

OTIMIZE-O!

Podemos melhorar o desempenho dessa função com uma margem muito grande com a simples adição de apenas mais dois caracteres no comando, assim:

{ 
echo identical identical
echo not_so_much as_before
echo abcdef bafcde
} | sed ':u;s/\(..*\)\(.*\)//p;tu'

OUTPUT

nt_so_much as_befre
ntso_much asbefre
nto_much abefre
nto_much abfr
nto_much abfr
bcdef bfcde
cdef fcde
f f

sed agora realiza negações em qualquer sequência de 1 ou mais caracteres que podem ser selecionados duas vezes, e é por isso que idêntico não aparece nos itens acima - é completamente negado na primeira passagem.

E sem p rint, os resultados são os mesmos:

{
echo identical identical
echo about_as_much as_before
echo abcdef bafcde
} | sed ':u;s/\(..*\)\(.*\)//;tu'

OUTPUT

ta_mch fr

POSITIVO DO NEGATIVO

Requer muito pouco mais - e não mais recursão - para negar a negação.

{
echo identical identical
echo not_so_much as_before
echo abcdef bafcde
} | sed 'h;:u;s/\(..*\)\(.*\)//;tu
    / ./{H;g;
    s/^/NOT FULL MATCH:\t/
    s/\n/\n\t%:\t/;b}
    g;s/^/FULL MATCH:\t/'

OUTPUT:

FULL MATCH:     identical identical
NOT FULL MATCH: not_so_much as_before
        %:      nto_much abfr
FULL MATCH:     abcdef bafcde

Ou apenas:

{
echo identical identical
echo not_so_much as_before
echo abcdef bafcde
} | sed -e ':u;s/\(..*\)\(.*\)//;tu' \
    -e '/ ./{cshite...' -e 'b};cHOORAY!'

OUTPUT:

HOORAY!
shite...
HOORAY!
    
por 09.05.2014 / 19:51
1

Para o conceito usando ferramentas shell sed / grep     ExistingSeq = '8_, 1_, 2_, 3_, 4_, 5_, 9_, 7_, 6 _'

NewSeq="5_,2_,1_,4_"

# prepa
SizeTemp=$( echo "${NewSeq}" | sed -e 's/[^,]//g;s/^/,/' )
Size=${#SizeTemp}
echo "${NewSeq}" | sed -e 's/,/\
,/g;s/^/,/' > /tmp/ToFind

# search
InsideOcc=$( echo "${ExistingSeq}" | sed -e 's/,/\
,/g' | egrep -c -f /tmp/ToFind )

# test
echo "test with an if on 'InsideOcc' [${InsideOcc}] is lower (not present) or equivalent (present) to Size: [${Size}] "

rm /tmp/ToFind

para ser eficiente e evitar muito sed similar, trabalhe com arquivo de índice (temporário) com um elemento por linha.

Agora, essa não é uma boa maneira de criar um índice de arquivos enorme, especialmente devido ao tempo exponencial solicitado no comprimento da sequência e no comprimento do índice. O AWK é certamente mais rápido em uma ocorrência de ferramentas de teste por sequência e somente memória (nenhum arquivo temporário que consuma tempo para gerenciar)

    
por 09.05.2014 / 17:00
1

Aqui está outra técnica: crie uma "chave" de uma string classificando seus caracteres:

gawk '
    function generate_key(s,  n,a,i,s2) {
        if (s in cached) return cached[s]
        n = split(s, a, //)
        asort(a)
        for (i=1; i<=n; i++) s2 = s2 a[i]
        cached[s] = s2
        return s2
    }
    {
        key = generate_key($1)
        status = (key in seen) ? "no" : "yes"
        print $1, key, status
        seen[key]++
    }
' OFS="\t" <<END
123
231
321
312
1_,2_,4_,5_
5_,2_,1_,4_
2_,5_,1_,4_
END
123 123 yes
231 123 no
321 123 no
312 123 no
1_,2_,4_,5_ 1245,,,____ yes
5_,2_,1_,4_ 1245,,,____ no
2_,5_,1_,4_ 1245,,,____ no
    
por 09.05.2014 / 22:55
0

se o arquivo de indexação é composto apenas por linhas de 6 caracteres.
Isso corresponderá a qualquer combinação de "abcdef" no arquivo de índice

grep a indexfile | grep b | grep c | grep d |grep e | grep f

se o arquivo de índice for mais complicado, use sed para extrair os índices.

    
por 10.05.2014 / 00:50

Tags