简体   繁体   中英

How to select the nth char from a string for each line in a file?

Every line has a word and a number. I need somehow to select the nth letter which all together will make a new word. For example:

and 3
for 3
map 2
wrestle 1

draw

it has to start like this

cat char.txt | ...

and I'm only allowed to use sed (no awk, perl, ...).

I know how to select all the numbers

sed 's/\(.*\) \(.*\)/\2/g'

or the 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 it won't work because it won't iterate thought all the lines and for some reason it won't even work on a single line.

Need some help and guidance pls

Ty

while read w n; do echo -n ${w:(($n-1)):1}; done < filename

Output:

draw

${parameter:offset:length}: 
   Substring Expansion. Expands to up to length characters of parameter
   starting at the character specified by offset.

Here is a sed script solving the puzzle, assuming that 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 pads the word on the current line with @ s to ensure that there is at least 10 characters in the word field. The 9 subsequent lines replace the pattern space with the character at the given position. The H stores that character in the hold-space, preceded by a newline character. Unless the last line has been read, we discard the pattern space and start-over again. If the last line has been read, we exchange the pattern space with the hold space, which holds the desired word spammed with newline characters, which we remove.

Saving this in a file script.sed we obtain

% sed -f script.sed < data
draw

The charming exercise of implementing a version supporting character offsets in the range 1—19 is left as an exercise to the reader.

We can more easily solve this puzzle with awk :

% awk '{answer=answer substr($1,$2,1)}END{print(answer)}' < data
draw

using only sed (sorry to avoid the 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 take column 1 to 9 (single digit) but could be extended with adaptation to "huge number". It also, by 'simplicity' write the word 1 char per line (so verticaly). Could also be modified bu overload the code.

Explaination

principle: if last digit is not 1, remove first char and decrease by 1. If it is equal to 1, print the 1st char of the line.

  • test if last digit is 1 by /1$/
  • Decrease is done by the translation y/98765432/87654321/
  • remove of first char by s/.//
  • other is presentation using working and holding buffer (to modify only last digit part) by copying the line, leave only the digit, decrease, add the original line and rearrange new digit in place of last old one
  • reaching digit = 1, in does not enter to the process and keep only 1st char, then print it by s/\\(.\\).*/\\1/p

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM