Search code examples
swiftcocoaterminalnstask

How to handle tabulated terminal output after NSTask command execution with Swift


I managed to execute terminal command from OSX app but the problem is that the data is tabulated. So I'm kindly asking if someone knows how to parse this to some data structure from where I can get single value in specific row and column. The other problem I'm facing is that there is text before the tabulated data, which I think I need to skip so I can grab the value (I don't know).

Here is example of the data.

this is very special output and we are proud of it.
0x0032   099   099   000
0x0032   099   099   000
0x0013   099   099   000
0x0013   122   100   010
0x0032   100   100   010
0x0032   100   100   010
0x0013   100   100   010
0x0032   100   100   000

So for example I need to get the value: 122 which is in 4th row 2nd column from left to right. How I can do this with Swift code.

Please help.


Solution

  • I suppose the right answer is to actually know your expected output and then parse out the stuff you want to keep (regex, etc. to find the lines that match what you want "I might have a line of initial output I can throw out. Then I always have 4 columns, separated by 3 spaces where data in X position looks like \d{3}"). That would probably be better so you can handle a variety of situations and address unexpected results.

    But - you could also do a kind of bad approximation of that by just arbitrarily saying:

    • I have a carriage returns that denotes "rows"
    • I have three spaces that denote "columns"
    • "real" data will always have the same number of columns
    • We don't know how many columns there will be, but we're going to make the assumption that we'll find the "max" and then that will define our number (EX: "real data" in this example has 4 columns, while "junk" data has one)
    • Throw out any rows that don't have the matching number of columns

      let stdOut = "this is very special output and we are proud of it.\n0x0032 099 099 000\n0x0032 099 099 000\n0x0013 099 099 000\n0x0013 122 100 010\n0x0032 100 100 010\n0x0032 100 100 010\n0x0013 100 100 010\n0x0032 100 100 000"

      var rowsAndCols: [[String]] = [[]]

      let rowDelimiter = "\n" //rows are split by carriage return let colDelimiter = " " //cols are split by 3 spaces

      let rows = stdOut.componentsSeparatedByString(rowDelimiter)

      for row in rows { let cols = row.componentsSeparatedByString(colDelimiter) rowsAndCols.append(cols) }

      //count the # of columns and get the max let maxCols = rowsAndCols.map({$0.count}).maxElement()

      //remove any rows whose # columns is lower than the "max" found rowsAndCols = rowsAndCols.filter({$0.count == maxCols})

      //show our whole output print(rowsAndCols)

      let someVal = rowsAndCols[0][0] print(someVal)