v21i029: String function to do sed(1)/tr(1) manipulations, Part02/03
Rich Salz
rsalz at uunet.uu.net
Sat Mar 24 06:11:11 AEST 1990
Submitted-by: Terry Jones <terry at pcsbst.pcs.com>
Posting-number: Volume 21, Issue 29
Archive-name: strsed/part02
#!/bin/sh
# this is part 2 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file strsed.c continued
#
CurArch=2
if test ! -r s2_seq_.tmp
then echo "Please unpack part 1 first!"
exit 1; fi
( read Scheck
if test "$Scheck" != $CurArch
then echo "Please unpack part $Scheck next!"
exit 1;
else exit 0; fi
) < s2_seq_.tmp || exit 1
echo "x - Continuing file strsed.c"
sed 's/^X//' << 'SHAR_EOF' >> strsed.c
X more_space(1);
X new_str[new_pos++] = *tmp++;
X }
X }
X
X /*
X * Move forward over the matched text.
X *
X */
X str += regs.end[0];
X str_len -= regs.end[0];
X }
X } while (global && match != -1 && *str);
X
X /*
X * Copy the final portion of the string. This is the section that
X * was not matched (and hence which remains unchanged) by the last
X * match. Then we head off home.
X *
X */
X more_space(str_len);
X (void) strcpy(new_str + new_pos, str);
X RETURN(new_str);
X}
X
X#define DIGIT(x) (isdigit(x) ? (x) - '0' : islower(x) ? (x) + 10 - 'a' : (x) + 10 - 'A')
X
Xstatic char *
Xbackslash_eliminate(str, type, who)
Xchar *str;
Xint type;
Xint who;
X{
X /*
X * Remove backslashes from the strings. Turn \040 etc. into a single
X * character (we allow eight bit values). Currently NUL is not
X * allowed.
X *
X * Turn "\n" and "\t" into '\n' and '\t' characters. Etc.
X *
X * The string may grow slightly here. Under normal circumstances
X * it will stay the same length or get shorter. It is only in the
X * case where we have to turn {a-z}{A-Z} into \0{a-z}{A-Z} that
X * we add two chars. This only happens when we are doing a REPLACEMENT.
X * So we can't overwrite str, and we have to
X * malloc. Sad, but the only ways I could find around it (at this
X * late stage) were really gross. I allowed an extra
X * 100 bytes which should cover most idiotic behaviour.
X * I count the extra space and exit nicely if they do do something
X * extremely silly.
X *
X * 'i' is an index into new_str.
X *
X * 'type' tells us how to interpret escaped characters.
X *
X * type = REGEX
X * if the pattern is a regular expression. If it is then
X * we leave escaped things alone (except for \n and \t and
X * friends).
X *
X * type = REPLACEMENT
X * if this is a replacement pattern. In this case we change
X * \( and \) to ( and ), but leave \1 etc alone as they are
X * register references. - becomes a metacharacter between
X * { and }.
X *
X * type = NORMAL
X * We do \n and \t elimination, as well as \040 etc, plus
X * all other characters that we find quoted we unquote.
X * type = NORMAL when we do a backslash elimination on the
X * string argument to strsed.
X *
X * who tells us where to tell mem where to stick the new string.
X *
X * \{m,n\} syntax (see ed(1)) is not supported.
X *
X */
X
X static char *mem();
X char *new_str;
X int extra = 100;
X int seenlb = 0;
X register int i = 0;
X register int seenbs = 0;
X int first_half = 0;
X
X if (type == REPLACEMENT){
X if (!(new_str = mem(who, strlen(str) + 1 + extra))){
X return 0;
X }
X }
X else{
X new_str = str;
X }
X
X while (*str){
X if (seenbs){
X seenbs = 0;
X switch (*str){
X case '\\':{
X new_str[i++] = '\\';
X str++;
X break;
X }
X
X case '-':{
X if (seenlb){
X /* Keep it quoted. */
X new_str[i++] = '\\';
X }
X new_str[i++] = '-';
X str++;
X break;
X }
X
X case '}':{
X if (seenlb){
X /* Keep it quoted. */
X new_str[i++] = '\\';
X }
X new_str[i++] = '}';
X str++;
X break;
X }
X
X case 'n':{
X new_str[i++] = '\n';
X str++;
X break;
X }
X
X case 't':{
X new_str[i++] = '\t';
X str++;
X break;
X }
X
X case 's':{
X new_str[i++] = ' ';
X str++;
X break;
X }
X
X case 'r':{
X new_str[i++] = '\r';
X str++;
X break;
X }
X
X case 'f':{
X new_str[i++] = '\f';
X str++;
X break;
X }
X
X case 'b':{
X new_str[i++] = '\b';
X str++;
X break;
X }
X
X case 'v':{
X new_str[i++] = '\13';
X str++;
X break;
X }
X
X case 'z':{
X str++;
X break;
X }
X
X case '0': case '1': case '2': case '3': case '4':
X case '5': case '6': case '7': case '8': case '9':{
X
X char val;
X
X /*
X * Three digit octal constant.
X *
X */
X if (*str >= '0' && *str <= '3' &&
X *(str + 1) >= '0' && *(str + 1) <= '7' &&
X *(str + 2) >= '0' && *(str + 2) <= '7'){
X
X val = (DIGIT(*str) << 6) +
X (DIGIT(*(str + 1)) << 3) +
X DIGIT(*(str + 2));
X
X if (!val){
X /*
X * NUL is not allowed.
X */
X return 0;
X }
X
X new_str[i++] = val;
X str += 3;
X break;
X }
X
X /*
X * One or two digit hex constant.
X * If two are there they will both be taken.
X * Use \z to split them up if this is not wanted.
X *
X */
X if (*str == '0' && (*(str + 1) == 'x' || *(str + 1) == 'X') && isxdigit(*(str + 2))){
X val = DIGIT(*(str + 2));
X if (isxdigit(*(str + 3))){
X val = (val << 4) + DIGIT(*(str + 3));
X str += 4;
X }
X else{
X str += 3;
X }
X
X if (!val){
X return 0;
X }
X
X new_str[i++] = val;
X break;
X }
X
X /*
X * Two or three decimal digits.
X * (One decimal digit is taken as either a register reference
X * or as a decimal digit if NORMAL is true below.)
X *
X */
X if (isdigit(*(str + 1))){
X val = DIGIT(*str) * 10 + DIGIT(*(str + 1));
X if (isdigit(*(str + 2))){
X val = 10 * val + DIGIT(*(str + 2));
X str += 3;
X }
X else{
X str += 2;
X }
X
X if (!val){
X return 0;
X }
X
X new_str[i++] = val;
X break;
X }
X
X /*
X * A register reference or else a single decimal digit if this
X * is a normal string..
X *
X * Emit \4 (etc) if we are not NORMAL (unless the digit is a 0
X * and we are processing an r.e. This is because \0 makes no
X * sense in an r.e., only in a replacement. If we do have \0
X * and it is an r.e. we return.)
X *
X */
X if (*str == '0' && type == REGEX){
X return 0;
X }
X
X if (type == NORMAL){
X if (!(val = DIGIT(*str))){
X return 0;
X }
X new_str[i++] = val;
X str++;
X }
X else{
X new_str[i++] = '\\';
X new_str[i++] = *str++;
X }
X break;
X }
X
X default:{
X if (type == REGEX){
X new_str[i++] = '\\';
X }
X new_str[i++] = *str++;
X break;
X }
X }
X }
X else{
X if (*str == '\\'){
X seenbs = 1;
X str++;
X }
X else if (type == REPLACEMENT && *str == '}'){
X if (*(str + 1) == '{' && first_half){
X new_str[i++] = *str++;
X new_str[i++] = *str++;
X first_half = 0;
X }
X else{
X seenlb = 0;
X new_str[i++] = *str++;
X }
X }
X else if (type == REPLACEMENT && !seenlb && *str == '{'){
X /*
X * Within { and }, \- should be left as such. So we can differentiate
X * between s/fred/\-/ and s/fred/{\-a-z}{+A-Z}
X *
X * We stick in a "\0" here in the case that \X has not just been
X * seen. (X = 0..9) Which is to say, {a-z}{A-Z} defaults to
X * \0{a-z}{A-Z}
X *
X */
X
X seenlb = 1;
X first_half = 1;
X
X if (i < 2 || new_str[i - 2] != '\\' || !(new_str[i - 1] >= '0' && new_str[i - 1] <= '9')){
X if ((extra -= 2) < 0){
X /* ran out of extra room. */
X return 0;
X }
X new_str[i++] = '\\';
X new_str[i++] = '0';
X }
X new_str[i++] = *str++;
X }
X else{
X /*
X * A normal char.
X *
X */
X new_str[i++] = *str++;
X }
X }
X }
X
X if (seenbs){
X /*
X * The final character was a '\'. Ignore it.
X *
X */
X }
X
X new_str[i] = '\0';
X return new_str;
X}
X
Xstatic char *
Xbuild_map(s, map)
Xchar *s;
Xchar *map;
X{
X /*
X * Produce a mapping table for the given transliteration.
X * We are passed something that looks like "{a-z}{A-Z}"
X * Look out for \ chars, these are used to quote } and -.
X *
X * Return a pointer to the char after the closing }.
X * We cannot clobber s.
X *
X * The building of maps is somewhat optimised.
X * If the string is the same as the last one we were
X * called with then we don't do anything. It would be better
X * to remember all the transliterations we have seen, in
X * order (because in a global substitution we will
X * apply them in the same order repeatedly) and then we
X * could do the minimum amount of building. This is a
X * compromise because it is a fairly safe bet that there will
X * not be more than one transliteration done.
X *
X */
X
X char *in;
X char *out;
X char *str;
X char *tmp;
X char c;
X static char *mem();
X static char nextch();
X int i = 0;
X int range_count = 0;
X int seenbs = 0;
X static char *last = 0;
X static int last_len;
X
X if (!s){
X return 0;
X }
X
X if (last && !strncmp(s, last, last_len)){
X /* Re-use the map. */
X return s + last_len;
X }
X else{
X /*
X * Make a copy of s in both 'last' and 'str'
X */
X int len = strlen(s) + 1;
X if (!(str = mem(MEM_MAP, len)) || !(last = mem(MEM_MAP_SAVE, len))){
X return 0;
X }
X str[0] = last[0] = '\0';
X strcat(str, s);
X strcat(last, s);
X }
X
X tmp = str + 1;
X in = str;
X
X while (*tmp){
X if (seenbs){
X if (*tmp == '-'){
X /*
X * Keep the \ before a - since this is the range
X * separating metacharacter. We don't keep } quoted,
X * we just put it in. Then it is passed as a normal
X * char (no longer a metachar) to nextch().
X *
X */
X str[i++] = '\\';
X }
X str[i++] = *tmp++;
X seenbs = 0;
X }
X else{
X if (*tmp == '\\'){
X seenbs = 1;
X tmp++;
X }
X else if (*tmp == '}'){
X if (!range_count){
X /* seen first range. */
X range_count = 1;
X str[i++] = '\0';
X tmp++;
X while (*tmp == ' ' || *tmp == '\t'){
X tmp++;
X }
X if (*tmp != '{'){
X return 0;
X }
X out = str + i;
X tmp++;
X }
X else{
X /* seen both ranges. */
X str[i++] = '\0';
X tmp++;
X range_count = 2;
X break;
X }
X }
X else{
X /* A plain defenceless character. */
X str[i++] = *tmp++;
X }
X }
X }
X
X if (range_count != 2){
X return 0;
X }
X
X last_len = tmp - str;
X
X /*
X * Now 'out' and 'in' both point to character ranges.
X * These will look something like "A-Z" but may be
X * more complicated and have {} and - in them elsewhere.
X *
X */
X
X for (i = 0; i < 1 << BYTEWIDTH; i++){
X map[i] = i;
X }
X
X /*
X * Ready the range expanding function.
X *
X */
X (void) nextch(in, 0);
X (void) nextch(out, 1);
X
X /*
X * For each char in 'in', assign it a value in
X * 'map' corresponding to the next char in 'out'.
X *
X */
X
X while ((c = nextch(0, 0))){
X map[c] = nextch(0, 1);
X }
X
X return tmp;
X}
X
Xstatic char
Xnextch(str, who)
Xchar *str;
Xint who;
X{
X /*
X * Given a range like {a-z0237-9}
X * return successive characters from the range on
X * successive calls. The first call (when str != 0)
X * sets things up.
X *
X * We must handle strange things like
X * {a-b-c-z} = {a-z}
X * and {z-l-a} = {z-a}
X * and {f-f-f-f-h} = {f-h}
X * and {a-z-f-h-y-d-b} = {a-b}
X *
X * and so on.
X *
X * This function will remember two strings and will return
X * the next charcter in the range specified by 'who'. This
X * makes the building of the transliteration table above
X * a trivial loop.
X *
X * I can't be bothered to comment this as much as it
X * deserves right now... 8-)
X *
X */
X
X static char *what[2] = {0, 0};
X static char last[2] = {0, 0};
X static int increment[2];
X static int pos[2];
X
X if (who < 0 || who > 1){
X return 0;
X }
X
X if (str){
X /* Set up for this string. */
X what[who] = str;
X pos[who] = 0;
X return 1;
X }
X else if (!what[who]){
X return 0;
X }
X
X if (!pos[who] && what[who][0] == '-'){
X return 0;
X }
X
X switch (what[who][pos[who]]){
X
X case '-':{
X /* we're in mid-range. */
X last[who] += increment[who];
X if (what[who][pos[who] + 1] == last[who]){
X pos[who] += 2;
X }
X return last[who];
X }
X
X case '\0':{
X /*
X * We've finished. Keep on returning the
X * last thing you saw if who = 1.
X */
X if (who){
X return last[1];
X }
X return 0;
X }
X
X /* FALLTHROUGH */
X case '\\':{
X pos[who]++;
X }
X
X default:{
X last[who] = what[who][pos[who]++];
X /*
X * If we have reached a '-' then this is the start of a
X * range. Keep on moving forward until we see a sensible
X * end of range character. Then set up increment so that
X * we do the right thing next time round. We leave pos
X * pointing at the '-' sign.
X *
X */
X
X while (what[who][pos[who]] == '-'){
X int inc = 1;
X if (what[who][pos[who] + inc] == '\\'){
X inc++;
X }
X if (!what[who][pos[who] + inc]){
X return 0;
X }
X if (what[who][pos[who] + inc + 1] == '-'){
X pos[who] += inc + 1;
X continue;
X }
X increment[who] = what[who][pos[who] + inc] - last[who];
X if (!increment[who]){
X pos[who] += 2;
X continue;
X }
X if (increment[who] > 0){
X increment[who] = 1;
X break;
X }
X else if (increment[who] < 0){
X increment[who] = -1;
X break;
X }
X }
X return last[who];
X }
X }
X}
X
Xstatic char *
Xmem(who, size)
Xint who;
Xint size;
X{
X /*
X * Get 'size' bytes of memeory one way or another.
X *
X * The 'mem_slots' array holds currently allocated hunks.
X * If we can use one that's already in use then do so, otherwise
X * try and find a hunk not in use somewhere else in the table.
X * As a last resort call malloc. All a bit specialised and
X * not too clear. Seems to works fine though.
X */
X
X static void mem_save();
X
X if (who < 0 || who >= MEM_SLOTS){
X return 0;
X }
X
X if (mem_slots[who].used){
X /*
X * There is already something here. Either move/free it or
X * return it if it is already big enough to hold this request.
X */
X if (mem_slots[who].size >= size){
X /* It is already big enough. */
X return mem_slots[who].s;
X }
X else{
X mem_save(who);
X }
X }
X else{
X /*
X * The slot was not in use. Check to see if there is space
X * allocated here already that we can use. If there is and
X * we can, use it, if there is and it's not big enough try to
X * save it. if there isn't then try to find it in another free slot,
X * otherwise don't worry, the malloc below will get us some.
X */
X if (mem_slots[who].s && mem_slots[who].size >= size){
X /* We'll take it. */
X mem_slots[who].used = 1;
X return mem_slots[who].s;
X }
X
X if (mem_slots[who].s){
X mem_save(who);
X }
X else{
X static int mem_find();
X int x = mem_find(size);
X if (x != -1){
X mem_slots[who].s = mem_slots[x].s;
X mem_slots[who].size = mem_slots[x].size;
X mem_slots[who].used = 1;
X mem_slots[x].s = (char *)0;
X return mem_slots[who].s;
X }
X }
X }
X
X /*
X * Have to use malloc 8-(
X */
X
X if (!(mem_slots[who].s = malloc((unsigned)size))){
X return 0;
X }
X mem_slots[who].size = size;
X mem_slots[who].used = 1;
X
X return mem_slots[who].s;
X}
X
Xstatic int
Xmem_find(size)
Xint size;
X{
X /*
X * See if we can find an unused but allocated slot with 'size'
X * (or more) space available. Return the index, or -1 if not.
X */
X
X register int i;
X
X for (i = 0; i < MEM_SLOTS; i++){
X if (!mem_slots[i].used && mem_slots[i].s && mem_slots[i].size >= size){
X return i;
X }
X }
X return -1;
X}
X
Xstatic void
Xmem_save(x)
Xint x;
X{
X /*
X * There is some memory in mem_slots[x] and we try to save it rather
X * than free it. In order we try to
X *
X * 1) put it in an unused slot that has no allocation.
X * 2) put it in an unused slot that has an allocation smaller than x's
X * 3) free it since there are no free slots and all the full ones are bigger.
X *
X */
X
X register int i;
X register int saved = 0;
X
X /*
X * First we try to find somewhere unused and with no present allocation.
X */
X for (i = 0; i < MEM_SLOTS; i++){
X if (!mem_slots[i].used && !mem_slots[i].s){
X saved = 1;
X mem_slots[i].s = mem_slots[x].s;
X mem_slots[i].size = mem_slots[x].size;
X mem_slots[i].used = 0;
X break;
X }
X }
X
X /*
X * No luck yet. Try for a place that is not being used but which has
X * space allocated, and which is smaller than us (and all other such spots).
X * Pick on the smallest, yeah.
X */
X if (!saved){
X register int small = -1;
X register int small_val = 1000000;
X for (i = 0; i < MEM_SLOTS; i++){
X if (!mem_slots[i].used && mem_slots[i].size < mem_slots[x].size && mem_slots[i].size < small_val){
X small_val = mem_slots[i].size;
X small = i;
X }
X }
X
X if (small != -1){
X saved = 1;
X /* We got one, now clobber it... */
X free(mem_slots[small].s);
X /* and move on in. */
X mem_slots[small].s = mem_slots[x].s;
X mem_slots[small].size = mem_slots[x].size;
X mem_slots[small].used = 0;
X }
X }
X
X if (!saved){
X /* Have to toss it away. */
X free(mem_slots[x].s);
X }
X}
X
Xstatic void
Xmem_init()
X{
X /*
X * Clear all the memory slots.
X */
X
X register int i;
X
X for (i = 0; i < MEM_SLOTS; i++){
X mem_slots[i].s = (char *)0;
X mem_slots[i].used = 0;
X }
X}
X
Xstatic void
Xmem_free(except)
Xchar *except;
X{
X /*
X * "Clear out" all the memory slots. Actually we do no freeing since
X * we may well be called again. We just mark the slots as unused. Next
X * time round they might be useful - the addresses and sizes are still there.
X *
X * For the slot (if any) whose address is 'except', we actually set the
X * address to 0. This is done because we are called ONLY from the macro
X * RETURN() in strsed() and we intend to return the value in 'except'.
X * Once this is done, strsed should (in theory) have no knowledge at all
X * of the address it passed back last time. That way we won't clobber it
X * and cause all sorts of nasty problems.
X */
X
X register int i;
X
X for (i = 0; i < MEM_SLOTS; i++){
X mem_slots[i].used = 0;
X if (mem_slots[i].s == except){
X mem_slots[i].s = (char *)0;
X mem_slots[i].size = 0;
X }
X }
X}
X
SHAR_EOF
echo "File strsed.c is complete"
chmod 0644 strsed.c || echo "restore of strsed.c fails"
set `wc -c strsed.c`;Sum=$1
if test "$Sum" != "36532"
then echo original size 36532, current size $Sum;fi
echo "x - extracting Makefile (Text)"
sed 's/^X//' << 'SHAR_EOF' > Makefile &&
X#
X# Makefile for strsed
X#
X
X#
X# Use gcc if you have it...
X# (The MIPS cc produces a regex.o which dumps core).
X#
X
X#CC = cc
X
XCC = gcc
XCFLAGS = -O
X
X
Xall : check
X
Xcheck : check1 check2
X cat examples1 | ./check1
X cat examples2 | ./check2
X
Xcheck1 : strsed.o regex.o check1.o
X $(CC) $(CFLAGS) -o check1 strsed.o regex.o check1.o
X
Xcheck2 : strsed.o regex.o check2.o
X $(CC) $(CFLAGS) -o check2 strsed.o regex.o check2.o
X
Xstrsed.o : regex.h
Xregex.o : regex.h
X
Xclean :
X rm -f check?.o
X
Xclobber : clean
X rm -f strsed.o check[12] MANIFEST
SHAR_EOF
chmod 0644 Makefile || echo "restore of Makefile fails"
set `wc -c Makefile`;Sum=$1
if test "$Sum" != "526"
then echo original size 526, current size $Sum;fi
echo "x - extracting check1.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > check1.c &&
X#include <stdio.h>
X
Xint
Xmain()
X{
X /*
X * Check simple searching.
X *
X * Input consists of sets of three lines containing
X *
X * text
X * pattern
X * expected new text
X *
X * See the file examples1
X *
X */
X
X extern int strcmp();
X extern char *strsed();
X
X char text[1024];
X char pat[1024];
X char ans[1024];
X register char *result;
X register int testno = 0;
X int error = 0;
X
X while (gets(text) && gets(pat) && gets(ans)){
X testno++;
X result = strsed(text, pat, 0);
X if (strcmp(ans, result)){
X error = 1;
X printf("WARNING (test %d)... strsed(%s, %s) returns '%s'\nExpected '%s'\n",
X testno, text, pat, result, ans);
X fflush(stdout);
X }
X }
X
X if (!error){
X printf("Substitution and transliteration tests passed successfully.\n");
X }
X
X return 0;
X}
SHAR_EOF
chmod 0644 check1.c || echo "restore of check1.c fails"
set `wc -c check1.c`;Sum=$1
if test "$Sum" != "775"
then echo original size 775, current size $Sum;fi
echo "x - extracting check2.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > check2.c &&
X#include <stdio.h>
X
Xint
Xmain()
X{
X /*
X * Check simple searching.
X *
X * Input consists of sets of four lines containing
X *
X * text
X * pattern
X * expected start of match
X * expected end of match
X *
X * See the file examples2
X *
X */
X
X extern int atoi();
X extern char *strsed();
X
X char text[1024];
X char pat[1024];
X char ans1[10];
X char ans2[10];
X int range[2];
X int low;
X int high;
X register int testno = 0;
X int error = 0;
X
X while (gets(text) && gets(pat) && gets(ans1) && gets(ans2)){
X testno++;
X strsed(text, pat, range);
X low = atoi(ans1);
X high = atoi(ans2);
X if (low != range[0] || high != range[1]){
X error = 1;
X printf("WARNING (test %d)... strsed(%s, %s) returns range %d-%d (Expected %d-%d)\n",
X testno, text, pat, range[0], range[1], low, high);
X fflush(stdout);
X }
X }
X
X if (!error){
X printf("Searching tests passed successfully.\n");
X }
X
X return 0;
X}
SHAR_EOF
chmod 0644 check2.c || echo "restore of check2.c fails"
set `wc -c check2.c`;Sum=$1
if test "$Sum" != "907"
then echo original size 907, current size $Sum;fi
echo "x - extracting examples1 (Text)"
sed 's/^X//' << 'SHAR_EOF' > examples1 &&
Xabcdef
Xs/bx?m?m?m?1?2?3?c/BC/
XaBCdef
Xabcdef
Xs/bx?c/BC/
XaBCdef
X/initial/slash
X/^\///
Xinitial/slash
Xfunny ranges
X/.*/{n-a-\--\040-\0xd-\d-n}{1-\x-\--\--p-7-1}/
Xfu11y ra1ges
Xfunny ranges
X/.*/{n-a-\--\040-\0xd-\d-n}{1-\x-\--\--p-7-4}/
Xfu11y ra1ges
Xfunny ranges
X/.*/{r-a-\--\040-\0xd-\d-u}{1-\x-\--\--p-7-4}/
Xf4nny 1ange2
Xfunny ranges
X/.*/{r-a-\--\d-u}{1-\x-\--\--p-7-4}/
Xf4nny 1ange2
Xfunny ranges
X/.*/{r-a-l-d-u}{1-x-p-7-4}/
Xf4nny 1ange2
Xfunny ranges
X/.*/{a-f-c}{1-9}/
Xfunny r1nges
Xhere we go
X/.*/{e}{\}}/
Xh}r} w} go
Xhere we go
X/.*/{e}{\-}/
Xh-r- w- go
Xhere we go
X/.*/{hre}{{\}\-}/
X{-}- w- go
X this is a line
Xg/\([\t\s]*\)\(.\)\([^\t\s]*\)/\1\2{a-z}{A-Z}\3/
X This Is A Line
Xjooooneees waaaassss heeeerrrrrreeeee
Xg/\([a-z\s]\)\1+/\1/
Xjones was here
Xtry an inverse range
Xg/[^e]/X/
XXXXXXXXXXXeXXeXXXXXe
Xtry an inverse range
Xg/[^a-z]/X/
XtryXanXinverseXrange
Xcapitalise first letters of words, preserving whitespace
Xg/\([\t\s]*\)\(.\)\([a-z]*\)/\1\2{a-z}{A-Z}\3/
XCapitalise First Letters Of Words, Preserving Whitespace
Xthis is a test of squeezing
Xg/\([a-z]\)\1*/\1/
Xthis is a test of squezing
Xjooooneees waaaassss heeeerrrrrreeeee
Xg/\([a-z\s]\)\1*/\1/
Xjones was here
Xmary had a little lamb
X/\(.*\) \(h.*\) \(a.*\)/"\0" becomes "\1{a-z}{A-Z} fucked \3{a-z}{A-C-E-XYZ}"/
X"mary had a little lamb" becomes "MARY fucked A LITTLE LAMB"
Xmary had a little lamb
X/\(.*\) \(.*\) \(.*\)/"\0" becomes "\1{a-z}{A-Z} fucked \3{a-z}{A-C-E-XYZ}"/
X"mary had a little lamb" becomes "MARY HAD A fucked LAMB"
Xmary had a little lamb
X/\(mary \(had\).*\)/{a-z}{A-Z}\1{had}{sex}/
XMARY HAD A LITTLE LAMBmery sex e little lemb
Xjones
Xg/ones/{a-c-f-n-qr-v-z}{A-J-Z}/
XjONES
Xa string an a another a ay?
Xg/a/{a-a-a-a-a-a-a-a-a-a-a-a}{X-X-X-X-Z}/
XX string Xn X Xnother X Xy?
Xa string an a another a ay?
X/.*/{a-a-a-a-a-a-a-a-a-a-a-ast}{X-X-X-X-Z}/
XX YZring Xn X XnoZher X Xy?
Xfred
X/\(.*\)/\1\s\1{a-z}{A-Z}\s\1{fred}{0123}\sjoe/
Xfred FRED 0123 joe
Xjordan k. hubbard
Xg/r/{a-z}{R}/
XjoRdan k. hubbaRd
Xjordan k. hubbard
Xg/r/{a-z}{A-Z}/
XjoRdan k. hubbaRd
Xjordan k. hubbard
Xg/r/R/
XjoRdan k. hubbaRd
Xterry jones was here
Xs/.*/{a-z}{A-Z}/
XTERRY JONES WAS HERE
Xfred he's dead
Xs/.* \(.*\) .*/\1{a-z}{1-9}/
X85'9
Xthis is a test line
Xg/\(.\)./{a-z}{A-Z}/
XTHIS IS A TEST LINe
Xthis is a test line
Xg/\(.\)./\1{a-z}{A-Z}/
XTI SATS Ie
Xthis is a test line
Xg/\(.\)\(.\)/\1{a-z}{A-Z}\2/
XThIs iS A TeSt lIne
Xthis is a test linex
Xg/\(.\)\(.\)/\1{a-z}{A-Z}\2/
SHAR_EOF
echo "End of part 2"
echo "File examples1 is continued in part 3"
echo "3" > s2_seq_.tmp
exit 0
--
Please send comp.sources.unix-related mail to rsalz at uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.
More information about the Comp.sources.unix
mailing list