3

I am struggling with the following. I am using commands like this in my Mac terminal to test my regex:

echo 'inputstring' | sed (-E) '/s///g'

I am trying to create a regex that:

  • if and only if a word ends in the letter 'o', then:
  • deletes this word-final 'o'
  • replaces all occurrences of the letter 'i' to 'a' in this word

In this case, the inputstring is filo fililo felo fale and the expected output is fal falal fel fale

I can make a regex that does either the deletion or the replacement, but do not see how to combine them. If I put a semi column between them, I don't see how to put in the conditional part.

I am also having trouble defining 'the end of the word' position. I used \b but it doesn't seem to work (unlike $ for end of string).

  • post the actual, testable input string – RomanPerekhrest Nov 19 '17 at 20:28
  • Good point, I just added this to the description. As well as the expected outcome. – Triplesmeg Nov 19 '17 at 20:34
  • sed won't be good for such case. Use awk instead – RomanPerekhrest Nov 19 '17 at 20:49
  • sed idea; replace words that end in 'o' with '#word#' with stripped 'o', replace all 'i' between two '#' with 'a', remove all '#' that appear immediately before/after a word (replace my example '#' with any suitable character). – Hannu Nov 19 '17 at 21:22
2

I would not use sed for this, but if this is an exercise to learn sed, do a loop like this:

sed -E 's/$/ /
  :a
  s/i([[:alnum:]]*o[^[:alnum:]])/a\1/
  ta
  s/([[:alnum:]]*)o([^[:alnum:]])/\1\2/
  ta
  s/ $//'
  • In the first line I add a whitespace at the end, so we can treat the line end like any word end. The last line removes that whitespace later.
  • The s command in line 3 searches for occurences of i in a word ending with o and replaces it with a. The t command loops back to mark :a to repeat this for all i in all o-ending words.
  • Now the fifth line removes the ending o and another loop. Note that from a word ending with oo, both of them will get removed; it's unclear whether this is desired.

For references only, I use an sed version supporting the o option to the s command meaning only to preserve the matched part and throw away the rest. Also it knows the \h in the replacement to replace by the contents of the hold space. This makes the task a one-liner:

sed -E ':a;h;s/([[:alnum:]]*)o($|[^[:alnum:]])/\1\2/o;T;y/i/a/;x;s//\h/;ba'
1

Awk would be more accurate and flexible for such case:

awk '{ for(i=1;i<=NF;i++) 
       if ($i~/o$/) { sub(/o$/,"",$i); gsub("i","a",$i) } }1' <<<"filo fililo felo fale"

The output:

fal falal fel fale

Alternative Python command line approach:

python -c 'import sys,re; s = sys.stdin.read().strip(); 
print(re.sub(r"\b(\S+)o\b", lambda m: m.group(1).replace("i","a"), s))' <<<"filo fililo felo fale"
fal falal fel fale
0

I'm not sure if this is possible to do with sed (I suspect that it probably isn't), but it's really easy to do with Python! Here's a script that does exactly what you want:

#!/usr/bin/env python2
# -*- coding: ascii -*-
"""modify_strings.py"""

import sys
import re
import fileinput

# Iterate over lines of input
# (either read from files or from stdin)
for line in fileinput.input():

    # Split each line into tokens and preserve whitespace
    tokens = re.split(r'(\s+)', line)

    # Iterate over tokens
    for token in tokens:

        # If a word ends in 'o' then
        # perform the desired transformation
        if token.endswith('o'):
            token = token[:-1].replace('i', 'a')

        # Print out each token
        sys.stdout.write(token)

You can run it like so:

echo 'filo fililo felo fale' | python modify_strings.py

And it produces the following output (as desired):

fal falal fel fale

If you really want sed to be involved, then you can probably get what you want by augmenting it with a little shell scripting. That might look something like the following bash script:

#!/usr/bin/env bash

# modify-strings.bash

for word in "$@"; do
    if grep -q 'o$' <<<"${word}"; then
        echo -n "${word} " | sed -e 's/i/a/g' -e 's/o$//';
    else
        echo -n "${word} ";
    fi;
done
echo

You would call this script like so:

bash modify-strings.bash filo fililo felo fale
  • Everything is possible with sed, the question is whether it makes sense. In this case, I don't think so, see my answer for a solution. – Philippos Nov 20 '17 at 8:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.