How do I select nth char from a string for each line in a file?
Each line has a word and a number. I need to somehow select the nth letter that together will make a new word. For example:
and 3
for 3
map 2
wrestle 1
draw
it should start like this
cat char.txt | ...
and I'm allowed to use sed (no awk, perl, ...).
I know how to pick all numbers
sed 's/\(.*\) \(.*\)/\2/g'
or text
sed 's/\(.*\) \(.*\)/\1/g'
and I was thinking about
cat char.txt | head -c $(sed 's/\(.*\) \(.*\)/\2/g') | tail -c 1 | sed 's/\n\//g'
but that won't work because it won't go over the thoughts of all lines and for some reason won't work even on one line.
Need help and advice.
Tee
source to share
Here is a sed script solution to solve the puzzle, assuming the numbers found are in the range 1-9:
s/ /@@@@@@@@@@ /
s/\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\).* 1$/\1/
s/\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\).* 2$/\2/
s/\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\).* 3$/\3/
s/\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\).* 4$/\4/
s/\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\).* 5$/\5/
s/\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\).* 6$/\6/
s/\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\).* 7$/\7/
s/\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\).* 8$/\8/
s/\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\).* 9$/\9/
H
$!D
${x;s/\n//g;}
The first lines put the word on the current line with @
to ensure that there are at least 10 characters in the word field. The 9 subsequent lines replace the pattern space with the character at that position. H
stores this character in holdspace preceded by a newline character. If the last line was not read, we discard the pattern space and start over. If the last line has been read, we exchange the pattern space with the hold space, which contains the search word spammed with newlines, which we delete.
By saving this in a file script.sed
, we get
% sed -f script.sed < data
draw
A lovely exercise in implementing a version that supports character offsets in the 1-19 range is left as an exercise for the reader.
We can easily solve this riddle with awk
:
% awk '{answer=answer substr($1,$2,1)}END{print(answer)}' < data
draw
source to share
using sed only (sorry to avoid cat char.txt: -;
sed -n ':a
/1$/ !{
s/.//
h
s/.* \([0-9]\)$/\1/
y/98765432/87654321/
G
s/\(.\)\n\(.*\) [0-9]/\2 \1/
b a
}
s/\(.\).*/\1/p' char.txt
Assuming you only accept column 1-9 (one digit), but could be expanded to accommodate "huge number". In addition, "simplicity" writes the word 1 char per string (so vertically). The code that overloads the code can also be changed.
Explaination
: if the last digit is not 1, remove the first char and decrease by 1. If it is 1, print the 1st char of the string.
- if the last digit is 1 on
/1$/
- Reduction is done by translation
y/98765432/87654321/
- remove the first char by
s/.//
- the other is a representation using a working and holding buffer (to change only the last digit) by copying the string, leaving only the digit, decrementing, adding the original string, and changing the new digit instead of the last old one.
- reaching digit = 1, in is not included in the process and only the 1st char is stored and then printed on
s/\(.\).*/\1/p
source to share