3

I've been trying to use sed for aggregating a specific string pattern within a text for hours, but can't find the solution. I hope you guys know how to do it!?

  • The text subject to my Goal consists of string characters only (No invisible \t present).
  • I want to find string parts which contain (TAB), but at least two next to each other and maximum 8 adjacent to each other and replace them by a single (TAB) entry.

  • The search shall be performed within a Shell file, containing a bash script

Example:

#!/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'`
  • I have tried several Versions of the sed-command, the one above is just one of them. My original idea was modText=`echo $text | sed 's/\(TAB\)\{1\})\{2,8\}/(TAB)/g'`

Would be really great if you could help me out. Got the Feeling that the solution is not so far away but just don't have any more ideas and my research didn't do it :-S


Text Example

"Column One(TAB)(TAB)(TAB)Column Two(TAB)(TAB)Column three(TAB)Column4"

My search criteria would be matched by the first two (TAB) Groups, occurring between "Column One" and "Column three".

The result shall look like this:

"Column One(TAB)Column Two(TAB)Column three(TAB)Column4"

1
  • No, it's a real issue for me, but I tried to formulate it clean and simple. I am actually working on a Shell script that will reformat entire files. The handling of this is just one issue in the way to get it done. Jul 19, 2016 at 6:36

2 Answers 2

4

I'm not sure I understand how the "maximum 8" clause is supposed to apply, but the naive approach would be something like this:

sed 's/\((TAB)\)\{2,8\}/(TAB)/g'
8
  • The condition of max. 8 came from the idea that a series of (TAB) stands for a different type of formatting and therefore should be handled differently. Jul 19, 2016 at 6:45
  • just tried your Approach and it works on Shell Level (not in my bash script). Maybe it's because I've been working with a function. Jul 19, 2016 at 6:47
  • function reduceMultitabToSingle(){ eval param1="$1" retval=echo $param1 | sed 's/((TAB)\{2,8\}/(TAB)/g'` echo "reducing TABS to single:"$retval nline=$retval }` Jul 19, 2016 at 6:47
  • 1
    Then you can do this: sed 's/\((TAB)\)\{8\}/(TAB8)/g; s/\((TAB)\)\{2,7\}/(TAB)/g Jul 19, 2016 at 6:47
  • 1
    @Silverlight If this answer solved your issue, please take a moment and accept it by clicking on the check mark to the left. That will mark the question as answered and is the way thanks are expressed on the Stack Exchange sites. Also, if you want to answer someone's comment, don't leave any space between the @ and the user name. Welcome to the site!
    – terdon
    Jul 19, 2016 at 10:39
3

If you mean that the replacement should not be done if there are more than 8 adjacent (TAB)s, you could do:

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'

If your sed (like ssed) supports perl-like regexps, you can use look-around operators:

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

Or use perl directly:

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

AT&T (ast-open) sed, with the -A/-X option supports a kind of extended regular expressions they call augmented that have a negation operator (x!) and conjunction operator (x&y). There, (.{5}&(\(TAB\))!) matches a sequence of 5 characters that is not (TAB). So with that sed, you can do something like:

sed -A '
  :1
    s/(^.{0,4}|.{5}&(\(TAB\))!)(\(TAB\)){2,8}(.{0,4}$|.{5}&(\(TAB\))!)/\1(TAB)\4/
  t1'
4
  • Is ssed still around? The last version I'm aware of was released some ~10 years ago. The addition of Perl regexps was a nice idea but as I remember it conflicted with various system scripts with embedded \<mumble>, so it was eventually abandoned. I think the author moved to work on GNU sed. Jul 19, 2016 at 7:04
  • Not sure, the System I have to work with does not recognize the command Jul 19, 2016 at 7:10
  • Suppose reverted replacement can simplify sed script: replace >8 (TAB)s for some symbols, then replace 2-7 (TABS)s, then back 8's+ s/\((TAB)\)\{8\}/\a\a\a\a\a\a\a\a/g;:a;s/\a(TAB)/\a\a/g;ta;s/(TAB)(TAB)\+/(TAB)/g;s/\a/(TAB)/g
    – Costas
    Jul 19, 2016 at 7:30
  • @SatoKatsura, it doesn't seem to have changed much if at all in the last 10 years but it's still available as a package on Debian. Jul 19, 2016 at 11:16

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .