3

I have this text:

```python
x = 1
```

Basically markdown python cells. I would like to extract the content of the cell surrounding the cursor, if any.

As you may have guessed already, I am trying to build a jupyter workflow, I use jupytex and vim-slime for the console, and I would like to send cells to the console.

Currently I am struggling just matching a cell with regex:

/```python\(\(```\)\@!\)*```

This should match a string starting with ```python, then everything except triple quotes, then triple quotes, but it doesn't.

Strangely, this one(without the ending triple quotes:

/```python\(\(```\)\@!\)*

highlights ```python, but nothing more.

So what would be a regex to match a python cell? Bonus for a regex that matches the content of the cell under cursor!

1

2 Answers 2

4

This should match a string starting with ```python, then everything except triple quotes, then triple quotes, but it doesn't.

That's because the * multi does not repeat any character; it just repeats a negative lookahead, which doesn't add anything to the overall match. The regex engine can't reach the closing triple backticks.

/```python\(\(```\)\@!\)*```
            ^--------^
                ✘

Add a character inside:

/```python\(\(```\)\@!\_.\)*```
                      ^-^

Note that \_. can match any character, including a newline; contrary to . which can't match a newline. See :h /\_.


So what would be a regex to match a python cell? Bonus for a regex that matches the content of the cell under cursor!

Try this:

```python\n\%(\%(```\)\@!\_.\)*\%#\_.\{-}\n```\n
                               ├─┘   ├──┘
                               │     └ as few as possible
                               └ the cursor position must match here

See :h /\%#, and :h /\{-.

5
  • 1
    I've checked against your sample file, and it works. Note that your cursor needs to be inside a python cell for a match to be found.
    – user938271
    Commented Aug 20, 2020 at 20:31
  • That's perfect! Thank you. Commented Aug 20, 2020 at 20:59
  • And for only selecting the content of the cell: /\(```python\n\)\@<=\%(\%(```\)\@!\_.\)*\%#\_.\{-}\(```\)\@= Commented Aug 20, 2020 at 21:06
  • @NickSkywalker The vim help recommends using \zs and \ze instead of lookarounds when possible, for performance reasons. In this instance, they result in a slightly simpler regular expression, too, as you can dispense with some of the capture groups: /```python\n\zs\%(\%(```\)\@!\_.\)*\%#\_.\{-}\ze```
    – Rich
    Commented Aug 21, 2020 at 10:37
  • Thank you, I was sure there was something like this, that's a lot better :) Commented Aug 21, 2020 at 12:15
4

I don't understand those advanced regexes, but this one should do:

^```python\_$\_.\{-}\_^```$

To understand it, let :help ordinary_atom guide us:

  • \_$ matches end-of-line.
  • \_. matches any character, including end-of-lines.
  • \_^ matches start-of-line.

And with :help non-greedy,

  • \{-} is the same as * but uses the shortest match first algorithm. Remember that it applies only to the previous element, \_. in our case.

You may want to relax the regex a bit, maybe removing the ^ and $ anchoring.

Tested in this sample, the regex matches only the python cells.

This is Python:
```python
for i in range(10):
    print(i)
```
This is FORTRAN:
```fortran
DO I=1,10
    WRITE(*,*)I
ENDDO
```
This is Python again
```python
for i in range(10):
print('```')
```
1
  • 1
    Thanks for the answer! :) While this work the second answer matches better the question. Commented Aug 20, 2020 at 20:58

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.