1

I want to run a utility for replace values matching a regular expression. This means for every match of a regular expression, call the utility with the characters comprising the match. The output of the utility replaces the original characters.

For illustration purposes using factor:

$ factor 230
230: 2 5 23

So using this utility, I want to pick out the integers, call factor with the integer, and replace the original integer with the output of factor.

This is what I would expect on a sample input:

$ [code] <<< "Given the numbers with factors: 27, 13, 230, and 19, it is evident which are primes."
Given the numbers with factors: 27: 3 3 3, 13: 13, 230: 2 5 23, and 19: 19, it is evident which are primes.

I thought this might work, but it looks like it's trying to interpret the input directly. Using sed (GNU sed) 4.2.2.

$ sed -E 's/([0-9]+)/factor \1/ge' <<< 'Given the numbers with factors: 27, 13, 230, and 19, it is evident which are primes.'
sh: 1: Given: not found

Obviously I'm not understanding what the e flag does. Removing the e shows that the regular expression is correctly pulling out the integers and passing them as \1.

I tried doing this in awk:

$ awk '{r = gensub(/([0-9]+)/, system("factor \\1"), "g"); print r}' <<< 'Given the numbers with factors: 27, 13, 230, and 19, it is evident which are primes.'
1:
Given the numbers with factors: 0, 0, 0, and 0, it is evident which are primes.

I'm not sure where the 1: comes from, but it's apparent that it's printing just the return code from system. There doesn't appear to be a way to capture the standard output from a command in awk.

Is what I'm asking for possible using the core utilities?

  • elaborate your for every match in the input, because for now you are reversing all words. Post a testable input which would contain matched and non-matched items – RomanPerekhrest Jul 18 '18 at 13:48
  • @RomanPerekhrest – For every match of a regular expression, call a custom utility with the characters comprising the match. The output of the custom utility replaces the original characters. – Yimin Rong Jul 18 '18 at 13:52
  • again, Post a testable input which would contain matched and non-matched items. Also, elaborate if a regex pattern could cover a part of the word or the whole word only – RomanPerekhrest Jul 18 '18 at 13:57
  • @RomanPerekhrest - Replaced reverse with factor. People are fixated on this red herring. – Yimin Rong Jul 18 '18 at 14:39
1

Possible in Perl. Using split, map, scalar, lc, reverse, ucfirst, join. A bit more complex than I originally thought because of the commas and context sensitivity of matching.

#!/usr/bin/perl
use warnings;
use strict;

sub rev {
    my ($string) = @_;
    my @words = split /(\W+)/, $string;
    my @caps = map scalar(/^[[:upper:]]/), @words;
    $_ = /\w/ ? lc reverse : $_ for @words;
    shift @caps and $_ = ucfirst for @words;
    return join "", @words
}

use Test::More tests => 1;
my $r = rev('Hello, my name is Yimin Rong.');
is $r, 'Olleh, ym eman si Nimiy Gnor.';
  • Thanks, but I used reverse just as an illustration. The actual utility I need to use is much more complex. Imagine reverse as a black box not easily duplicated in a scripting language. – Yimin Rong Jul 18 '18 at 13:35
  • The trick is to write reverse in Perl, too ;-) – choroba Jul 18 '18 at 13:42
  • Trust me, what I'm using isn't easy in perl, think about a factoring utility using the general number field sieve. – Yimin Rong Jul 18 '18 at 13:46
  • @YiminRong: If it's easy in shell, it must be easy in Perl, too. – choroba Jul 18 '18 at 14:11
  • Rewrote to illustrate with factor. Good luck writing that in perl! – Yimin Rong Jul 18 '18 at 15:06
0

Try the below awk solution:

echo "Hello" | awk '{ for ( i=length($0);i>0;i-- ) { if (i == length($0) ) { printf "%s",toupper(substr($0,i,1)) } else {  printf "%s",tolower(substr($0,i,1)) } } printf "\n" }'

Take each letter of the word character by character stating from the last. If it is the last character, convert to upper case and print otherwise print lower case.

0

Run the following :

 perl -pe 's/(\d+)/qx(factor $1) =~ s|\n||r/ge'  input-file.txt

The reason why your sed command is not working is because sed will execute the entire pattern space unlike Perl which is aligned with how you were thinking and executes just as much as is on the rhs of the s/// command and replaces tonly that much with the command output.

And that's precisely why if you notice sed was cribbing abt "Given:" utility not found. Given was the beginning of your pattern space. HTH

-1

Run the following:

perl -pe 's/(\d+)/qx(factor $1) =~ s|\n||r/ge'  input-file.txt
  • Care to explain how this works? – Kusalananda Jul 20 '18 at 19:08

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.