How can I break this line?

I am trying to split the lines leading up to places where there is an integer, 2-digit number surrounded by spaces. In the end, I would like it to work in Python, but I worked with sed, and I can't figure it out.

My test data is as follows:

13 13 13 13 13 9:07.18 9:12.09 9:15.65 14 14 14 2:04.86 2:05.99 2:06.87 14 4:21.51 4:23.51 4:25.00 14 8:56.28 9:01.09 9:04.58 15 15 57.18 57.61 57.95 15 2:02.61 2:03.72 2:04.58 15 4:17.31 4:19.28 4:20.75 15 8:47.15 8:51.87 8:55.30 16 16 56.34 56.76 57.09 16 2:00.69 2:01.78 2:02.63 16 4:13.75 4:15.69 4:17.14 16 8:39.71 8:44.37 8:47.75 17 25.69 25.85 25.99 17 55.62 56.03 56.36 17 1:59.07 2:00.15 2:00.99 17 4:10.76 4:12.69 4:14.11 17 8:33.73 8:38.34 8:41.68 18 25.43 25.59 25.73 18 55.01 55.42 55.74 18 1:57.74 1:58.81 1:59.63 18 4:08.34 4:10.24 4:11.66 18 8:33.73 8:37.04 19 25.20 25.36 25.49 19 54.50 54.91 55.23 19 1:57.74 1:58.56 19 4:08.34 4:09.74 19 8:33.73 

And I would like it to be broken like this (pay attention to the location of the commas ','):

 13, 13, 13, 13, 13 9:07.18 9:12.09 9:15.65 14, 14, 14 2:04.86 2:05.99 2:06.87, 14 4:21.51 4:23.51 4:25.00, 14 8:56.28 9:01.09 9:04.58 15, 15 57.18 57.61 57.95, 15 2:02.61 2:03.72 2:04.58, 15 4:17.31 4:19.28 4:20.75, 15 8:47.15 8:51.87 8:55.30 16, 16 56.34 56.76 57.09, 16 2:00.69 2:01.78 2:02.63, 16 4:13.75 4:15.69 4:17.14, 16 8:39.71 8:44.37 8:47.75 17 25.69 25.85 25.99, 17 55.62 56.03 56.36, 17 1:59.07 2:00.15 2:00.99, 17 4:10.76 4:12.69 4:14.11, 17 8:33.73 8:38.34 8:41.68 18 25.43 25.59 25.73, 18 55.01 55.42 55.74, 18 1:57.74 1:58.81 1:59.63, 18 4:08.34 4:10.24 4:11.66, 18 8:33.73 8:37.04 19 25.20 25.36 25.49, 19 54.50 54.91 55.23, 19 1:57.74 1:58.56, 19 4:08.34 4:09.74, 19 8:33.73 

The above data is pretty regular in that double-digit integers are in the range [13,19], but the range I should expect is [10,99].

Can anyone suggest a method to perform the above conversion? I have been with this regex for a while, but I cannot cover all cases.

+5
source share
4 answers

A simplified statement (?=...) can solve the following:

 >>> a = """13 13 13 13 13 9:07.18 9:12.09 9:15.65 14 14 14 2:04.86 2:05.99 2:06.87 14 4:21.51 4:23.51 4:25.00 14 8:56.28 9:01.09 9:04.58 15 15 57.18 57.61 57.95 15 2:02.61 2:03.72 2:04.58 15 4:17.31 4:19.28 4:20.75 15 8:47.15 8:51.87 8:55.30 16 16 56.34 56.76 57.09 16 2:00.69 2:01.78 2:02.63 16 4:13.75 4:15.69 4:17.14 16 8:39.71 8:44.37 8:47.75 17 25.69 25.85 25.99 17 55.62 56.03 56.36 17 1:59.07 2:00.15 2:00.99 17 4:10.76 4:12.69 4:14.11 17 8:33.73 8:38.34 8:41.68 18 25.43 25.59 25.73 18 55.01 55.42 55.74 18 1:57.74 1:58.81 1:59.63 18 4:08.34 4:10.24 4:11.66 18 8:33.73 8:37.04 19 25.20 25.36 25.49 19 54.50 54.91 55.23 19 1:57.74 1:58.56 19 4:08.34 4:09.74 19 8:33.73""" >>> print(re.sub("(\d{2}) (?=\d{2}( |$))","\g<1>, ", a)) 13, 13, 13, 13, 13 9:07.18 9:12.09 9:15.65 14, 14, 14 2:04.86 2:05.99 2:06.87, 14 4:21.51 4:23.51 4:25.00, 14 8:56.28 9:01.09 9:04.58 15, 15 57.18 57.61 57.95, 15 2:02.61 2:03.72 2:04.58, 15 4:17.31 4:19.28 4:20.75, 15 8:47.15 8:51.87 8:55.30 16, 16 56.34 56.76 57.09, 16 2:00.69 2:01.78 2:02.63, 16 4:13.75 4:15.69 4:17.14, 16 8:39.71 8:44.37 8:47.75 17 25.69 25.85 25.99, 17 55.62 56.03 56.36, 17 1:59.07 2:00.15 2:00.99, 17 4:10.76 4:12.69 4:14.11, 17 8:33.73 8:38.34 8:41.68 18 25.43 25.59 25.73, 18 55.01 55.42 55.74, 18 1:57.74 1:58.81 1:59.63, 18 4:08.34 4:10.24 4:11.66, 18 8:33.73 8:37.04 19 25.20 25.36 25.49, 19 54.50 54.91 55.23, 19 1:57.74 1:58.56, 19 4:08.34 4:09.74, 19 8:33.73 

So reg exp. you need (\d{2}) (?=\d{2}( |$)) , which means:

  • (\d{2}) => Save 2 numbers in group 1 and map the extra space.
  • (?=\d{2}( |$)) => match 2 numbers and 1 space or EOL, but do not consume them.

The key point here is that without consuming the second matched group, it will be processed again the next time a subfunction is applied. Finally, \g<1>, will replace 1. with the same numbers and additional,.

+7
source

For the pleasure of sed, and because you seem to be interested in the sed link for understanding.

 sed ":a;s/\([^,]\)\(\s[0-9]\{2\}\s\)/\1,\2/;ta" 

or

 sed -E ":a;s/([^,])(\s[0-9]{2}\s)/\1,\2/;ta" 
  • start a cycle
    • look for
      • something different from, important for the cycle later
      • space, two digits and spaces
    • replace with no comma, comma and the rest
  • if it replaced something

Output (exactly the same as the desired output):

 13, 13, 13, 13, 13 9:07.18 9:12.09 9:15.65 14, 14, 14 2:04.86 2:05.99 2:06.87, 14 4:21.51 4:23.51 4:25.00, 14 8:56.28 9:01.09 9:04.58 15, 15 57.18 57.61 57.95, 15 2:02.61 2:03.72 2:04.58, 15 4:17.31 4:19.28 4:20.75, 15 8:47.15 8:51.87 8:55.30 16, 16 56.34 56.76 57.09, 16 2:00.69 2:01.78 2:02.63, 16 4:13.75 4:15.69 4:17.14, 16 8:39.71 8:44.37 8:47.75 17 25.69 25.85 25.99, 17 55.62 56.03 56.36, 17 1:59.07 2:00.15 2:00.99, 17 4:10.76 4:12.69 4:14.11, 17 8:33.73 8:38.34 8:41.68 18 25.43 25.59 25.73, 18 55.01 55.42 55.74, 18 1:57.74 1:58.81 1:59.63, 18 4:08.34 4:10.24 4:11.66, 18 8:33.73 8:37.04 19 25.20 25.36 25.49, 19 54.50 54.91 55.23, 19 1:57.74 1:58.56, 19 4:08.34 4:09.74, 19 8:33.73 
0
source

By adding VMRuiz to the response , this displays a list for each line, not one large line. I had to change the regex to use re.split instead of re.sub , and I'm not sure if it is equivalent.

 for line in a.split('\n'): re.split('(?<=\d{2}) (?=\d{2} |$)', line) 

Edit: this is definitely the same, but a bit inconvenient:

 for line in re.sub('(\d{2}) (?=\d{2}( |$))', '\g<1>,', a).split('\n'): line.split(',') 
0
source

If you want a non-regex Python solution, you can do:

 s = """\ 13 13 13 13 13 9:07.18 9:12.09 9:15.65 14 14 14 2:04.86 2:05.99 2:06.87 14 4:21.51 4:23.51 4:25.00 14 8:56.28 9:01.09 9:04.58 15 15 57.18 57.61 57.95 15 2:02.61 2:03.72 2:04.58 15 4:17.31 4:19.28 4:20.75 15 8:47.15 8:51.87 8:55.30 16 16 56.34 56.76 57.09 16 2:00.69 2:01.78 2:02.63 16 4:13.75 4:15.69 4:17.14 16 8:39.71 8:44.37 8:47.75 17 25.69 25.85 25.99 17 55.62 56.03 56.36 17 1:59.07 2:00.15 2:00.99 17 4:10.76 4:12.69 4:14.11 17 8:33.73 8:38.34 8:41.68 18 25.43 25.59 25.73 18 55.01 55.42 55.74 18 1:57.74 1:58.81 1:59.63 18 4:08.34 4:10.24 4:11.66 18 8:33.73 8:37.04 19 25.20 25.36 25.49 19 54.50 54.91 55.23 19 1:57.74 1:58.56 19 4:08.34 4:09.74 19 8:33.73""" res="" for line in s.splitlines(): buf=line.split() for i, e in enumerate(buf[1:], 1): buf[i-1]+=", " if e.isdigit() else " " res+=''.join(buf)+"\n" >>> res 13, 13, 13, 13, 13 9:07.18 9:12.09 9:15.65 14, 14, 14 2:04.86 2:05.99 2:06.87, 14 4:21.51 4:23.51 4:25.00, 14 8:56.28 9:01.09 9:04.58 15, 15 57.18 57.61 57.95, 15 2:02.61 2:03.72 2:04.58, 15 4:17.31 4:19.28 4:20.75, 15 8:47.15 8:51.87 8:55.30 16, 16 56.34 56.76 57.09, 16 2:00.69 2:01.78 2:02.63, 16 4:13.75 4:15.69 4:17.14, 16 8:39.71 8:44.37 8:47.75 17 25.69 25.85 25.99, 17 55.62 56.03 56.36, 17 1:59.07 2:00.15 2:00.99, 17 4:10.76 4:12.69 4:14.11, 17 8:33.73 8:38.34 8:41.68 18 25.43 25.59 25.73, 18 55.01 55.42 55.74, 18 1:57.74 1:58.81 1:59.63, 18 4:08.34 4:10.24 4:11.66, 18 8:33.73 8:37.04 19 25.20 25.36 25.49, 19 54.50 54.91 55.23, 19 1:57.74 1:58.56, 19 4:08.34 4:09.74, 19 8:33.73 

In awk you can do:

 awk '{n=split($0,a) for (i=2;i<=n;i++) printf "%s%s", a[i-1], a[i]~/^[[:digit:]]+$/ ? ", " : " " print a[n] }' file 13, 13, 13, 13, 13 9:07.18 9:12.09 9:15.65 14, 14, 14 2:04.86 2:05.99 2:06.87, 14 4:21.51 4:23.51 4:25.00, 14 8:56.28 9:01.09 9:04.58 15, 15 57.18 57.61 57.95, 15 2:02.61 2:03.72 2:04.58, 15 4:17.31 4:19.28 4:20.75, 15 8:47.15 8:51.87 8:55.30 16, 16 56.34 56.76 57.09, 16 2:00.69 2:01.78 2:02.63, 16 4:13.75 4:15.69 4:17.14, 16 8:39.71 8:44.37 8:47.75 17 25.69 25.85 25.99, 17 55.62 56.03 56.36, 17 1:59.07 2:00.15 2:00.99, 17 4:10.76 4:12.69 4:14.11, 17 8:33.73 8:38.34 8:41.68 18 25.43 25.59 25.73, 18 55.01 55.42 55.74, 18 1:57.74 1:58.81 1:59.63, 18 4:08.34 4:10.24 4:11.66, 18 8:33.73 8:37.04 19 25.20 25.36 25.49, 19 54.50 54.91 55.23, 19 1:57.74 1:58.56, 19 4:08.34 4:09.74, 19 8:33.73 
0
source

Source: https://habr.com/ru/post/1267149/


All Articles