1

I have plenty of Python2 files with pattern like this

datetime(2019, 04, 11)
datetime(2019, 10, 01)
datetime(2019, 04, 05, 1, 1)

To migrate this code into Python3 I have to remove leading 0 in 2nd and 3rd datetime argument.

I know how to use sed for simple patterns like this:

sed  -e 's/01/1/g' -e 's/02/2/g' -e 's/03/3/g'  my.py

But my pattern is more sophisticated: I should modify only 2nd and 3rd argument of datetime(). How to do it with sed or any other command-line tool?

The following command tries to find all strings to be modified in codebase with simple static pattern like this:

  find . -name "*.py" | xargs grep datetime |  grep '01\|02\|03\|04\|05\|06\|07'

But it also has the same problem as above: the grep pattern is not specific enough - the pattern above should not look at entire string, only on 2nd and 3rd argument of datetime().

Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
user3440012
  • 171
  • 2
  • 12
  • 2
    `sed 's/ 0/ /g'`? – Cyrus Aug 01 '21 at 01:35
  • If `sed 's/ 0/ /g'` isn't all you need then [edit] your question to provide more truly representative sample input out, especially cases where `datetime()` as leading `0`s in the 4th or 5th arguments. – Ed Morton Aug 01 '21 at 14:43

4 Answers4

2

For your particular example, Python's 2to3 tool is helpful.

You can focus only on the numliteral conversions and then convert those.

Given:

$ cat f.py
datetime(2019, 04, 11)
datetime(2019, 10, 01)
datetime(2019, 04, 05, 1, 1)

You can do:

$ 2to3 -n -w --add-suffix=3 -f numliterals f.py
RefactoringTool: Refactored f.py
--- f.py    (original)
+++ f.py    (refactored)
@@ -1,3 +1,3 @@
-datetime(2019, 04, 11)
-datetime(2019, 10, 01)
-datetime(2019, 04, 05, 1, 1)
+datetime(2019, 0o4, 11)
+datetime(2019, 10, 0o1)
+datetime(2019, 0o4, 0o5, 1, 1)
RefactoringTool: Writing converted f.py to f.py3.
RefactoringTool: Files that were modified:
RefactoringTool: f.py

Having replaced 04 with 0o4 now you have a much more tangible target for a regex:

$ sed -E 's/([[:space:]]*)0o([[:digit:]]+)/\1\2/g' f.py3
datetime(2019, 4, 11)
datetime(2019, 10, 1)
datetime(2019, 4, 5, 1, 1)
dawg
  • 98,345
  • 23
  • 131
  • 206
1

You can do it like so:

find . -name "*.py" | xargs -d'\n' sed -i '/datetime/s/0\([0-9]\)/\1/g'
KamilCuk
  • 120,984
  • 8
  • 59
  • 111
0

Consider using \( ... \) expression for matching and saving the datetime(..., part:

$ cat example.py | sed  -e 's/\(datetime([^,]*,[ ]*\)0/\1/g' | sed  -e 's/\(datetime([^,]*,[^,]*,[ ]*\)0/\1/g'
datetime(2019, 4, 11)
datetime(2019, 10, 1)
datetime(2019, 4, 5, 1, 1)
Doj
  • 1,244
  • 6
  • 13
  • 19
  • 2
    Consider avoiding the [useless `cat`](https://stackoverflow.com/questions/11710552/useless-use-of-cat) and combining the two `sed` scripts into one. – tripleee Aug 01 '21 at 14:45
0

This might work for you (GNU sed):

sed -E 's/(datetime\([0-9]+, )0?([0-9]+, )0?([0-9]+)/\1\2\3/' file

Pattern match on the string datetime and only capture the non-zero leading numbers in the 2nd and 3rd parameters.

potong
  • 55,640
  • 6
  • 51
  • 83