Add x ^ 2 to each non-zero coefficient with sed / awk

I need to write a script or a command that should use awk or / and sed as simple as possible. Input file:

23 12 0 33 3 4 19 

1st row n = 3
2nd row n = 2
Each line of the file has a line of numbers. Each number is a coefficient, and we must add x ^ n, where n is the highest degree (the sum of the spaces between the numbers in each line (without a space after the last number in each line)), and if in our line "0", skip it. So, for this input we will output as:

 23x^3+12x^2+33 3x^2+4x+19 

Please help me write a short script to solve this problem. Thank you so much for your time and all the help :) My idea:

 linescount=$(cat numbers|wc -l) linecounter=1 While[linecounter<=linescount]; do i=0 for i in spaces=$(cat numbers|sed 1p | sed " " ) do sed -i 's/ /x^spaces/g' i=($(i=i-1)) done linecounter=($(linecounter=linecounter-1)) done 
+5
source share
9 answers

The following awk may help you in the same.

 awk '{for(i=1;i<=NF;i++){if($i!="" && $i){val=(val?val "+" $i:$i)(NF-i==0?"":(NF-i==1?"x":"x^"NF-i))} else {pointer++}};if(val){print val};val=""} pointer==NF{print;} {pointer=""}' Input_file 

Adding another form of liners here.

 awk ' { for(i=1;i<=NF;i++){ if($i!="" && $i){ val=(val?val "+" $i:$i)(NF-i==0?"":(NF-i==1?"x":"x^"NF-i))} else { pointer++}}; if(val) { print val}; val="" } pointer==NF { print} { pointer="" } ' Input_file 


EDIT: Adding explanation here for a better understanding of OP and all the people studying here.

 awk ' { for(i=1;i<=NF;i++){ ##Starting a for loop from variable 1 to till the value of NF here. if($i!="" && $i){ ##checking if variable i value is NOT NULL then do following. val=(val?val "+" $i:$i)(NF-i==0?"":(NF-i==1?"x":"x^"NF-i))} ##creating variable val here and putting conditions here if val is NULL then ##simply take value of that field else concatenate the value of val with its ##last value. Second condition is to check if last field of line is there then ##keep it like that else it is second last then print "x" along with it else keep ##that "x^" field_number-1 with it. else { ##If a field is NULL in current line then come here. pointer++}}; ##Increment the value of variable named pointer here with 1 each time it comes here. if(val) { ##checking if variable named val is NOT NULL here then do following. print val}; ##Print the value of variable val here. val="" ##Nullifying the variable val here. } pointer==NF { ##checking condition if pointer value is same as NF then do following. print} ##Print the current line then, seems whole line is having zeros in it. { pointer="" ##Nullifying the value of pointer here. } ' Input_file ##Mentioning Input_file name here. 
+3
source

Offering a Perl solution, because it has several higher levels than bash, which make the code a little easier:

 use strict; use warnings; use feature qw(say); my @terms; while (my $line = readline(*DATA)) { chomp($line); my $degree = () = $line =~ / /g; my @coefficients = split / /, $line; my @terms; while ($degree >= 0) { my $coefficient = shift @coefficients; next if $coefficient == 0; push @terms, $degree > 1 ? "${coefficient}x^$degree" : $degree > 0 ? "${coefficient}x" : $coefficient; } continue { $degree--; } say join '+', @terms; } __DATA__ 23 12 0 33 3 4 19 

Output Example:

 hunter@eros  ~  perl test.pl 23x^3+12x^2+33 3x^2+4x+19 

Any information that you want to use for any of the built-in functions used above: readline, chomp, push, shift, split, say and join can be found in perldoc with perldoc -f <function-name>

+2
source
 $ cat a.awk function print_term(i) { # Don't print zero terms: if (!$i) return; # Print a "+" unless this is the first term: if (!first) { printf " + " } # If it the last term, just print the number: if (i == NF) printf "%d", $i # Leave the coefficient blank if it 1: coef = ($i == 1 ? "" : $i) # If it the penultimate term, just print an 'x' (not x^1): if (i == NF-1) printf "%sx", coef # Print a higher-order term: if (i < NF-1) printf "%sx^%s", coef, NF - i first = 0 } { first = 1 # print all the terms: for (i=1; i<=NF; ++i) print_term(i) # If we never printed any terms, print a "0": print first ? 0 : "" } 

Example input and output:

 $ cat file 23 12 0 33 3 4 19 0 0 0 0 1 0 1 17 $ awk -f a.awk file 23x^3 + 12x^2 + 33 3x^2 + 4x + 19 0 x^2 + 1 17 
+2
source
 $ cat ip.txt 23 12 0 33 3 4 19 5 3 0 34 01 02 $ # mapping each element except last to add x^n $ # -a option will auto-split input on whitespaces, content in @F array $ # $#F will give index of last element (indexing starts at 0) $ # $i>0 condition check to prevent x^0 for last element $ perl -lane '$i=$#F; print join "+", map {$i>0 ? $_."x^".$i-- : $_} @F' ip.txt 23x^3+12x^2+0x^1+33 3x^2+4x^1+19 5x^2+3x^1+0 34x^2+01x^1+02 $ # with post processing $ perl -lape '$i=$#F; $_ = join "+", map {$i>0 ? $_."x^".$i-- : $_} @F; s/\+0(x\^\d+)?\b|x\K\^1\b//g' ip.txt 23x^3+12x^2+33 3x^2+4x+19 5x^2+3x 34x^2+01x+02 
+2
source

One of the possibilities:

 #!/usr/bin/env bash line=1 linemax=$(grep -oEc '(( |^)[0-9]+)+' inputFile) while [ $line -lt $linemax ]; do degree=$(($(grep -oE ' +' - <<<$(grep -oE '(( |^)[0-9]+)+' inputFile | head -$line | tail -1) | cut -d : -f 1 | uniq -c)+1)) coeffs=($(grep -oE '(( |^)[0-9]+)+' inputFile | head -$line | tail -1)) i=0 while [ $i -lt $degree ]; do if [ ${coeffs[$i]} -ne 0 ]; then if [ $(($degree-$i-1)) -gt 1 ]; then echo -n "${coeffs[$i]}x^$(($degree-$i-1))+" elif [ $(($degree-$i-1)) -eq 1 ]; then echo -n "${coeffs[$i]}x" else echo -n "${coeffs[$i]}" fi fi ((i++)) done echo ((line++)) done 

The most important are:

 # Gets degree of the equation degree=$(($(grep -oE ' +' - <<<$(grep -oE '(( |^)[0-9]+)+' inputFile | head -$line | tail -1) | cut -d : -f 1 | uniq -c)+1)) # Saves coefficients in an array coeffs=($(grep -oE '(( |^)[0-9]+)+' inputFile | head -$line | tail -1)) 

Here grep -oE '(( |^)[0-9]+)+' finds strings containing only numbers (see edit). grep -oE ' +' - ........... |cut -d : -f 1 |uniq counts the number of coefficients per line, as described in this question .

Edit: improved regex for capturing strings with only numbers

  grep -E '(( |^)[0-9]+)+' inputfile | grep -v '[a-zA-Z]' 
+1
source
 sed -r "s/(.*) (.*) (.*) (.*)/\1x^3+\2x^2+\3x+\4/; \ s/(.*) (.*) (.*)/\1x^2+\2x+\3/; \ s/\+0x(^.)?\+/+/g; \ s/^0x\^.[+]//g; \ s/\+0$//g;" koeffs.txt 
  • Line 1: handle 4 items
  • Line 2: Knob 3
  • Line 3: Knob 0 in the middle
  • Line 5: Control 0 at startup
  • Line 5: Processing 0 at the end
+1
source

Here is a more miserable, less robust answer that reads better than sed, I think:

 #!/bin/bash # # 0 4 12 => 12x^3 # 2 4 12 => 12x # 3 4 12 => 12 term () { p=$1 leng=$2 fac=$3 pot=$((leng - 1 - p)) case $pot in 0) echo -n '+'${fac} ;; 1) echo -n '+'${fac}x ;; *) echo -n '+'${fac}x^$pot ;; esac } handleArray () { # mapfile puts a counter into the array, starting with 0 for the 1st # get rid of it! shift coeffs=($*) # echo ${coeffs[@]} cnt=0 len=${#coeffs[@]} while (( cnt < len )) do if [[ ${coeffs[$cnt]} != 0 ]] then term $cnt $len ${coeffs[$cnt]} fi ((cnt++)) done echo # -e '\n' # extra line for dbg, together w. line 5 of the function. } mapfile -n 0 -c 1 -C handleArray < ./koeffs.txt coeffs | sed -r "s/^\++//;s/\++$//;" 

The mapfile reads the data and creates an array. See help mapfile for a brief introduction to the syntax.

We need a calculation in order to know what power needs to be raised. In the meantime, we are trying to get rid of 0-terms.

In the end, I use sed to remove leading and trailing pluses.

+1
source

sh solution

 while read line ; do set -- $line while test $1 ; do i=$(($#-1)) case $1 in 0) ;; *) case $i in 0) j="" ;; 1) j="x" ;; *) j="x^$i" ;; esac result="$result$1$j+";; esac shift done echo "${result%+}" result="" done < infile 
+1
source
 $ cat tst.awk { out = sep = "" for (i=1; i<=NF; i++) { if ($i != 0) { pwr = NF - i if ( pwr == 0 ) { sfx = "" } else if ( pwr == 1 ) { sfx = "x" } else { sfx = "x^" pwr } out = out sep $i sfx sep = "+" } } print out } $ awk -f tst.awk file 23x^3+12x^2+33 3x^2+4x+19 
+1
source

Source: https://habr.com/ru/post/1276288/


All Articles