3
\$\begingroup\$

I have a sample svg file from the graphics program Inkscape. My objective is to collect every third pair from a very long line of floating point numbers. That seems simple enough. The larger objective is to write out svg code with calculated parameters - because Inkscape cannot do this in a "batch" mode - only "by hand" - all fine and doable.

I have a lengthy script (not shown) that gets the correct result, using bash, awk, grep, cut and sed - because I have a lot of such scripts to work from. I have looked at many other posts on Unix & Linux, which had some promise. Perhaps a single python or perl script would be better to write svg output, but I am trying to focus on individual steps of the ad-hoc script that works - the initial grep/sed/awk part - to make this appropriate for Stack Exchange.

The numbers are separated (if that is the correct word) by a comma, like this :

0.05306,-1.85438

I suppose I should show the line I am working on, apologies for the length. I am trying to preserve everything - including the leading spaces :

       d="m 53.049246,151.83874 c 0.05306,-1.85438 0.155553,-3.63727 0.304925,-5.35109 0.153133,-1.75698 0.355536,-3.44137 0.604459,-
5.05582 0.257082,-1.66737 0.563784,-3.26013 0.917074,-4.78117 0.399178,-1.7186 0.857832,-3.34565 1.371592,-4.88532 0.566073,-1.69644 
1.199045,-3.2868 1.893068,-4.77667 0.733396,-1.57438 1.534967,-3.03655 2.397812,-4.39309 0.897172,-1.4105 1.86059,-2.70681 2.882498,-
3.89632 1.158647,-1.34869 2.392483,-2.56009 3.690201,-3.64502 1.232816,-1.03066 2.523284,-1.94718 3.861711,-2.75883 1.457388,-0.88378
 2.97164,-1.6432 4.53024,-2.29024 1.538451,-0.63866 3.120112,-1.16782 4.732946,-1.59897 1.636238,-0.4374 3.304561,-0.77392 4.992402,-
1.02158 1.640903,-0.24077 3.300254,-0.39755 4.966504,-0.48136 1.661534,-0.0836 3.329929,-0.0946 4.993735,-0.044 1.679345,0.0511 3.354
014,0.16488 5.012237,0.33022 1.63047,0.16257 3.24504,0.37495 4.83252,0.62644 1.7341,0.27473 3.43586,0.59612 5.09071,0.95025 1.65289,0
.35371 3.25896,0.74008 4.80369,1.14522 1.69385,0.44425 3.31394,0.91106 4.8411,1.38213 1.64731,0.50813 3.1865,1.02121 4.59351,1.51626 
1.8366,0.6462 3.44798,1.26167 4.78064,1.79531 2.67181,1.06986 4.22329,1.81076 4.22329,1.81076"

... I note there are some letters in there too - in fact, the first pair has to be skipped - see the sed command. So the next step in this script is to get the remaining pairs. The following works but seems a terrible way to do it - because ideally, the processing script should handle any svg file Inkscape might produce :

input=for_script_test_01.svg
grep "\ d=" $input  | sed 's/^.\{33\}//' | sed 's/\"//g' | \
awk '{print $3, $6, $9, $12, $15, $18, $21, $24, $27, $30, $33, $36, $39, $42, $45, $48, $51, $54, $57, $60, $63, $66, $69, $72, $75, $78}'

the output is :

0.304925,-5.35109 0.604459,-5.05582 0.917074,-4.78117 1.371592,-4.88532 1.893068,-4.77667 2.397812,-4.39309 2.882498,-3.89632 3.690201,-3.64502 3.861711,-2.75883 4.53024,-2.29024 4.732946,-1.59897 4.992402,-1.02158 4.966504,-0.48136 4.993735,-0.044 5.012237,0.33022 4.83252,0.62644 5.09071,0.95025 4.80369,1.14522 4.8411,1.38213 4.59351,1.51626 4.78064,1.79531 4.22329,1.81076

that is clumsy to read - and might have typos even though I checked - so I tried to put the pairs in a single column using a clumsy one-liner on the output file > output.dat (note: the each $each is a typo, should be echo $each, but we are leaving it be):

user@local:/home$ my_list=`cat output.dat` ; for each in $my_list ; do each $each ; done

the last three lines of the output, to check :

4.59351,1.51626
4.78064,1.79531
4.22329,1.81076

... apologies for length. Hopefully the idea is clear.

UPDATE : this post on extracting path strings and lines from svg files using some svg parser modules in python will be helpful for working this out :

https://stackoverflow.com/questions/15857818/python-svg-parser

Related post on Graphic Design

\$\endgroup\$
5
  • 1
    \$\begingroup\$ does this work as intended? if not stackoverflow is probably the place to ask \$\endgroup\$
    – depperm
    Feb 24, 2023 at 17:27
  • 1
    \$\begingroup\$ it works and the larger script works - it calculates positions of circles to put in an svg - but I think that is beyond the scope here. I could have put the output but it is so long, I figured users can just run the one-liner to check. perhaps I'll put the last line. \$\endgroup\$ Feb 24, 2023 at 17:34
  • \$\begingroup\$ ... thank you, I discovered a typo - a . instead of a , in theawk call. I adjusted and added some output. \$\endgroup\$ Feb 24, 2023 at 17:43
  • 1
    \$\begingroup\$ Please do not edit the question, especially the code, after an answer has been posted. Changing the question may cause answer invalidation. Everyone needs to be able to see what the reviewer was referring to. What to do after the question has been answered. \$\endgroup\$
    – pacmaninbw
    Mar 11, 2023 at 13:43
  • \$\begingroup\$ @pacmaninbw apologies, perhaps I could put a note around it. \$\endgroup\$ Mar 14, 2023 at 19:46

2 Answers 2

3
\$\begingroup\$

awk is a very powerful programming language. If you plan to invoke it, you likely need neither grep nor sed.

sed is also a very powerful programming language. Assuming you already got the payload

0.155553,-3.63727 0.304925,-5.35109 0.153133,-1.75698 0.355536,-3.44137 0.604459,-5.05582 0.257082,-1.66737 0.563784,-3.26013 0.917074,-4.78117 0.399178,-1.7186 0.857832,-3.34565 1.371592,-4.88532 0.566073,-1.69644 1.199045,-3.2868 1.893068,-4.77667 0.733396,-1.57438 1.534967,-3.03655 2.397812,-4.39309 0.897172,-1.4105 1.86059,-2.70681 2.882498,-3.89632 1.158647,-1.34869 2.392483,-2.56009 3.690201,-3.64502 1.232816,-1.03066 2.523284,-1.94718 3.861711,-2.75883 1.457388,-0.88378 2.97164,-1.6432 4.53024,-2.29024 1.538451,-0.63866 3.120112,-1.16782 4.732946,-1.59897 1.636238,-0.4374 3.304561,-0.77392 4.992402,-1.02158 1.640903,-0.24077 3.300254,-0.39755 4.966504,-0.48136 1.661534,-0.0836 3.329929,-0.0946 4.993735,-0.044 1.679345,0.0511 3.354014,0.16488 5.012237,0.33022 1.63047,0.16257 3.24504,0.37495 4.83252,0.62644 1.7341,0.27473 3.43586,0.59612 5.09071,0.95025 1.65289,0.35371 3.25896,0.74008 4.80369,1.14522 1.69385,0.44425 3.31394,0.91106 4.8411,1.38213 1.64731,0.50813 3.1865,1.02121 4.59351,1.51626 1.8366,0.6462 3.44798,1.26167 4.78064,1.79531 2.67181,1.06986 4.22329,1.81076 4.22329,1.81076"

then

sed 's/[^ ]* [^ ]* \([^ ]*\)./\1\
/g'

produces

0.304925,-5.35109
0.604459,-5.05582
0.917074,-4.78117
1.371592,-4.88532
1.893068,-4.77667
2.397812,-4.39309
2.882498,-3.89632
3.690201,-3.64502
3.861711,-2.75883
4.53024,-2.29024
4.732946,-1.59897
4.992402,-1.02158
4.966504,-0.48136
4.993735,-0.044
5.012237,0.33022
4.83252,0.62644
5.09071,0.95025
4.80369,1.14522
4.8411,1.38213
4.59351,1.51626
4.78064,1.79531
4.22329,1.81076

Specifically, it replaces every three space-separated "words" with the last one, followed by a newline (if you have a GNU sed, a literal newline is not necessary: \n will suffice).

To extract the payload, use sed -n '/d=/s/[^m]*m [^ ]* c [^ ]* \(["]*\)"/\1/p'

\$\endgroup\$
6
  • \$\begingroup\$ excellent - in the first example command what is . and \1 called or what are they doing (so I can find it in info sed)? \$\endgroup\$ Feb 27, 2023 at 20:50
  • \$\begingroup\$ ...and in the second sed example, even if I do not suppress printing (-n) I do not see anything changing. Every "word" (as sed knows them) is preserved, so I think I am missing something... \$\endgroup\$ Feb 27, 2023 at 21:03
  • \$\begingroup\$ Re \1, pay attention to the \(...\). The latter is a capture. \1 prints the first capture, in thiks case the third word.g' does it globally. \$\endgroup\$
    – vnp
    Feb 28, 2023 at 4:31
  • \$\begingroup\$ so to print the 4th pair, we specify : [^ ]* [^ ]* [^ ]* \([^ ]*\)., to print the nth pair, we write n-1 of [^ ]* followed by the \([^ ]*\). \$\endgroup\$ Feb 28, 2023 at 17:26
  • \$\begingroup\$ ... also note the spaces - so [^ ]* [^ ]* will just pass right over the interesting bits, as the input only has one space, as in the middle of this: digits,digits digits,digits \$\endgroup\$ Feb 28, 2023 at 17:47
0
\$\begingroup\$

The question as stated is still open, but in the meantime, I found an alternative way around this problem, the source code of which one might look at for clues:

Use the program svg-path-interpolator described here, or the website alternative. In particular for this problem, I found a way to use awk to fix up the output - but not precisely as requested. Perhaps a clue might be found in it. But the overall objective is achieved with this.

So reading the linked question/answer on how to use svg-path-interpolator (there are other pitfalls I describe elsewhere), we take the example svg file above, and do the following (possible error : it looks like (i%2?$i:$i) should be $i) :

svgpi.mjs config.json for_script_test_01.svg | \
gawk -F, '
{
  gsub(/{|}|]/, "") ;
  gsub("\"[a-z]{4}_?([0-9]{1,14})?\":\\\[","") ;
  {
  for (i=1;i<=NF;i++)
  printf("%3.6f%s", (i%2?$i:$i), i%2?",":"\n")
  }
}' > for_script_test_01_coords.dat

the svgpi output (one line, 2351 characters by wc) is shown here. Nine x,y pairs, a hand-edit trim, then a trailing two x,y pairs, then a ]} cap - for illustration purposes only :

{"path857":[53,151.25,53,150.75,53,150.25,53,149.75,53,149.25,53,148.75,53,148.25,53,147.75,53.25,147.25[...snip...]132.75,116,133.25,116.25]}

The awk script above (I thank comp.lang.awk for help with that) converts the svgpi output into gnuplot-friendly form (for instance - beyond the scope), of which the first nine lines look like this:

53.000000,151.250000
53.000000,150.750000
53.000000,150.250000
53.000000,149.750000
53.000000,149.250000
53.000000,148.750000
53.000000,148.250000
53.000000,147.750000
53.250000,147.250000
[...snip...]

If anyone goes to do this, bear in mind that quadratics (q in the svg's path) might give strange results, so read this which says to use cairosvg to approximate them with cubics.

So this answer is more of a work-around, but based on what I learned in the intervening days since asking the basic question about getting "every third pair of (numbers)" (still working on that).

\$\endgroup\$
1
  • \$\begingroup\$ I also learned by now this question and answer isn't really what is called for by the Code Review Stack Exchange guidelines, but figured I'd follow through for completeness instead of ditching it. \$\endgroup\$ Mar 14, 2023 at 19:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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