Défi SED, agrégation Chaîne contenant des accolades

J'ai essayé d'utiliser sed pour agréger un model de string spécifique dans un text pendant des heures, mais je ne trouve pas la solution. J'espère que vous savez comment le faire!?

  • Le text soumis à mon objective se compose de caractères de string uniquement (pas de contenu invisible).
  • Je veux find des parties de string qui contiennent (TAB), mais au less deux à côté les uns des autres et maximum 8 adjacents les uns aux autres et les remplacent par une seule input (TAB).

  • La search doit être effectuée dans un file Shell contenant un script bash

Exemple:

#/!bin/bash text="Column One(TAB)(TAB)(TAB)Column Two(TAB)(TAB)Column three(TAB)Column4" modText=`echo $text | sed 's/([(]\{1\}TAB[)]\{1\})\{2,8\}/(TAB)/g'` 
  • J'ai essayé plusieurs versions de la command sed, celle ci-dessus n'est que l'une d'entre elles. Mon idée originale était modText = `echo $ text | sed 's / \ (TAB \) \ {1 \}) \ {2,8 \} / (TAB) / g'`

Serait vraiment génial si vous pouviez m'aider. J'ai le sentiment que la solution n'est pas si loin mais que je n'ai plus d'idées et que mes searchs ne l'ont pas fait: -S


Exemple de text

"Colonne un (TAB) (TAB) (TAB) Colonne deux (TAB) (TAB) Colonne trois (TAB) Colonne 4"

Mes critères de search seraient appariés par les deux premiers groupes (TAB), apparaissant entre "Colonne un" et "Colonne trois".

Le résultat doit ressembler à ceci:

"Colonne un (TAB) Colonne deux (TAB) Colonne trois (TAB) Colonne4"

Je ne suis pas sûr de comprendre comment la clause «maximum 8» est censée s'appliquer, mais l'approche naïve serait quelque chose comme ceci:

 sed 's/\((TAB)\)\{2,8\}/(TAB)/g' 

Si vous voulez dire que le rlocation ne devrait pas être fait s'il y a plus de 8 adjacents (TAB) , vous pourriez faire:

 sed ' s/_/_u/g; # escape _ s/|/_p/g; # escape | s/(TAB)/|/g; # use a single character in place of (TAB) s/.*/<&>/; # add leading and trailing non-| character s/\([^|]\)|\{2,8\}\([^|]\)/\1|\2/; # replace up to 8 | provided # they are not preceded nor followed # by | s/.\(.*\)./\1/; # undo wrapping s/|/(TAB)/g; # undo replacement s/_p/|/g;s/_u/_/g; # undo escaping' 

Si votre sed (comme ssed ) supporte les ssed perl-like, vous pouvez utiliser les opérateurs de look-around:

 ssed -R 's/(?<!\(TAB\))(\(TAB\)){2,8}(?!\(TAB\))/(TAB)/g' 

Ou utilisez directement perl :

 perl -lpe 's/(?<!\(TAB\))(\(TAB\)){2,8}(?!\(TAB\))/(TAB)/g' 

AT & T (ast-open) sed , avec l'option -A / -X supporte une sorte d'expressions régulières étendues appelées augmentées qui ont un opérateur de négation ( x! ) Et un opérateur de conjonction ( x&y ). Là, (.{5}&(\(TAB\))!) Correspond à une séquence de 5 caractères qui n'est pas (TAB) . Donc, avec ce sed , vous pouvez faire quelque chose comme:

 sed -A ' :1 s/(^.{0,4}|.{5}&(\(TAB\))!)(\(TAB\)){2,8}(.{0,4}$|.{5}&(\(TAB\))!)/\1(TAB)\4/ t1'