Reputation: 5974
I have a string, a sample of it looks like this:
There are patterns, generally after "Sequence:" the next 22 elements repeat, these are the data that I want isolated.
So I was thinking, if I split the string at Sequence:
into a list of elements and then split this generated list into a list of lists via \n
, each of these lists that had a length of 22 elements would be the data I wanted. So I've tried that with this code:
proc = subprocess.Popen(cmd_rancli, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
//proc_stdout is the string
proc_stdout = proc.communicate(ran_opt_get_access_data)[0]
parse = proc_stdout.split('Sequence:')
print parse
time.sleep(5)
parse2 = [i.split('\n')[0] for i in parse]
print parse2
time.sleep(5)
However the second of these doesn't give me what I expect, what am i doing wrong?
Actual output:
parse2 = ['RAN> get ap 108352 attr=4192', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '
', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']
Splitting and returning a space?
here is some of the result of the first parse: https://i.sstatic.net/sOQHP.png
Upvotes: 0
Views: 1930
Reputation: 31621
The reason you don't get what you expect is that there is whitespace between each Sequence:
and the following newline. [i.split('\n')[0] for i in parse]
will get the first item after splitting on newlines, which will be that whitespace.
Instead of fixing this approach, I suggest you do something slightly more sophisticated and create a dict that models your output:
def add_data(key, value, data):
if key.startswith('Value('):
if key.endswith('(int)'):
value = int(value)
data['Sequences'][-1].append(value)
elif key == 'Sequence':
data['Sequences'].append([])
else:
data[key] = value
def parse_lines(lineseq):
data = {'Sequences':[]}
for line in lineseq:
try:
key, value = [part.strip() for part in line.split(':', 1)]
except ValueError:
continue
add_data(key, value, data)
return data
lines = proc_stdout.split('\n')
data = parse_lines(lines)
This produces a data structure like so:
{'AttributeId': '4192',
'AttributeList': '',
'ClassId': '1014 (AP)',
'InstanceId': '0',
'MessageType': '81 (GetAttributesResponse)',
'ObjectInstance': '',
'Protocol': 'BSMIS Rx',
'RDN': '',
'TransactionId': '66',
'Sequences': [[],
[1,'2013-02-26T15:01:11Z'],
[],
[10564,13,388,0,-321,83,'272','05',67,67,708,896,31,128,-12,-109,0,-20,-111,-1,-1,0],
[10564,13,108,0,-11,83,'272','05',67,67,708,1796,31,128,-12,-109,0,-20,-111,-1,-1,0],
[10589,16,388,0,-15,79,'272','05',67,67,708,8680,31,125,-16,-110,0,-20,-111,-1,-1,0],
[10589,15,108,0,-16,81,'272','05',67,67,708,8105,31,126,-14,-109,0,-20,-111,-1,-1,0],
[10637,40,233,0,-11,89,'272','03',30052,1,5,54013,33,103,-6,-76,1,-20,-111,-1,-1,0],
[10662,46,234,0,-15,85,'272','03',30052,1,5,54016,33,97,-10,-74,1,-20,-111,-1,-1,0],
[10712,51,12,0,-24,91,'272','01',4013,254,200,2973,3,62,-4,-63,0,-20,-111,-1,-1,0],
[10737,15,224,0,-16,82,'272','01',3020,21,21,40770,33,128,-13,-108,0,-20,-111,-1,-1,0],
[10762,14,450,0,-7,78,'272','01',3020,21,21,53215,29,125,-17,-113,0,-20,-111,-1,-1,0],
[10762,15,224,0,-7,85,'272','01',3020,21,21,50770,33,128,-10,-105,0,-20,-111,-1,-1,0],
[10762,14,124,0,-7,78,'272','01',3020,10,10,56880,32,128,-17,-113,0,-20,-111,-1,-1,0],
[10812,11,135,0,-14,81,'272','02',36002,1,11,43159,31,130,-14,-113,1,-20,-111,-1,-1,0],
[10837,42,23,0,-9,89,'272','02',36002,1,11,53529,31,99,-6,-74,1,-20,-111,-1,-1,0,54],
[13,'2013-02-26T15:02:09Z'],
[],
[2,12,7,0,9,70,'272','02',20003,0,0,15535,0,0,0,0,1,100,100,-1,-1,0],
[5,15,44,0,-205,77,'272','02',20003,0,0,15632,0,0,0,0,1,100,100,-1,-1,0],
[7,25,9,0,0,84,'272','02',20002,0,0,50883,0,0,0,0,1,100,100,-1,-1,0]]
}
If you then only want sequences with a length of 22, it's easy to get that:
len22seqs = [s for s in data['Sequences'] if len(s)==22]
# alternatively:
len22seqs = filter(lambda s: len(s)==22, data['Sequences'])
Upvotes: 1
Reputation: 20997
Using string you provided on pastebin (as content of variable a
):
>>> result = [i.strip().split('\n') for i in a.split('Sequence')]
>>> [len(i) for i in result]
[10, 1, 3, 1, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 3, 1, 23, 23, 23]
For example here:
Sequence:
Value(int): 1
Value(string): 2013-02-26T15:01:11Z
Sequence:
So let's filter only those with 23 elements (note the first element is :
):
>>> result = [i[1:] for i in result if len(i) == 23]
>>> [len(i) for i in result]
[22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22]
And now you have array which looks like this:
>>> print( '\n'.join(result[0]))
Value(int): 10564
Value(int): 13
Value(int): 388
Value(int): 0
Value(int): -321
Value(int): 83
Value(string): 272
Value(string): 05
Value(int): 67
Value(int): 67
Value(int): 708
Value(int): 896
Value(int): 31
Value(int): 128
Value(int): -12
Value(int): -109
Value(int): 0
Value(int): -20
Value(int): -111
Value(int): -1
Value(int): -1
Value(int): 0
So whole code you need with data you provided is:
proc_stdout = proc.communicate(ran_opt_get_access_data)[0].decode('utf-8')
result = [i.strip().split('\n') for i in proc_stdout.split('Sequence')]
result = [i[1:] for i in result if len(i) == 23]
# Or at least [i[1:] for i in result if len(i) > 1]
We'll use simple hack, thus there's always only one :
and string.find()
and string.strip()
to remove white spaces:
def filter_value(text):
index = text.find( ':')
# Not found :
if index < 0:
return text.strip()
return text[index+1:].strip()
And implement it by replacing this line:
result = [i[1:] for i in result if len(i) == 23]
With this one-liner:
result = [[filter_value(j) for j in i[1:]] for i in result if len(i) == 23]
Upvotes: 2