re.search неожиданно заканчивается None, когда запускается под MSYS2 (и читает файл)? - PullRequest
1 голос
/ 30 сентября 2019

Итак, вот в чем дело: я написал фрагмент кода Python, простой парсер файлов журнала, дома, под Ubuntu Linux. Код работал отлично.

Теперь я возвращаюсь к работе, и здесь у меня есть машина с Windows 10, на которой я установил MSYS2, и я использую его Pythons (как 2, так и 3). Теперь, когда я запускаю тот же код в том же файле, я получаю:

AttributeError: 'NoneType' object has no attribute 'group'

... когда код встречается, скажем m.group(1), что фактически означает, что переменная mНет.

Вот тестовый скрипт, test.py, который устанавливает ту же строку и то же регулярное выражение - за исключением, к сожалению, он не воспроизводит ошибку:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import sys,os
import re

line = """TEST001 sample     1/00001: X: 1 Y: 1 Z: 1 TEMPC: 25.95°C
"""
m = re.search(r"""X: (\d+?) Y: (\d+?) Z: (\d+?) TEMPC: ([\d.]+?)°C""", line)
print(line, m, type(line))

Обратите внимание, чтовсе концы строк выше \n (то есть обычный LF)

Если я сейчас запусту это с Pythons в MSYS2 - либо по умолчанию для MSYS2 (на /usr/bin/python{2,3}, то есть C:\msys64\usr\bin\python{2,3}.exe, либоPython 3, который у меня есть в оболочке MINGW64, который находится в /mingw64/bin/python3 (то есть C:\msys64\mingw64\bin\python3.exe):

user@PC MSYS /tmp
$ python2 test.py
('TEST001 sample     1/00001: X: 1 Y: 1 Z: 1 TEMPC: 25.95\xc2\xb0C\n', <_sre.SRE_Match object at 0x6ffffffcca8>, <type 'str'>)

user@PC MSYS /tmp
$ python3 test.py
TEST001 sample     1/00001: X: 1 Y: 1 Z: 1 TEMPC: 25.95°C
 <re.Match object; span=(28, 57), match='X: 1 Y: 1 Z: 1 TEMPC: 25.95°C'> <class 'str'>

user@PC MSYS /tmp
$ /mingw64/bin/python3 test.py
TEST001 sample     1/00001: X: 1 Y: 1 Z: 1 TEMPC: 25.95�C
 <re.Match object; span=(28, 57), match='X: 1 Y: 1 Z: 1 TEMPC: 25.95�C'> <class 'str'>

Обратите внимание, что MSYS2 Python2 не может действительно печатать символ UTF-8 для градусов(что ожидается); MSYS2 Python3 может напечатать этот символ - но MINGW64 Python3 снова не может напечатать этот символ, хотя он должен?!

В любом случае - я запускаю свой настоящий рабочий скрипт влибо оболочка MSYS2 или MINGW64, явно с использованием /mingw64/bin/python3, так как моя настоящая работаСкрипт должен использовать matplotlib и numpy, и они могут быть установлены только для оболочки MINGW64 ... Однако, там, как я уже говорил, программа на самом деле вылетает, поскольку в результате m = re.search(...) получается, что m становится None.


РЕДАКТИРОВАТЬ: код, который я имею в моем фактическом рабочем сценарии:

  with open(file_abspath, 'rt') as thelogfile:
    for line in thelogfile:
      if "something" in line: ...
      elif line.startswith("TEST001 sample"):
        m = re.search(r"""X: (\d+?) Y: (\d+?) Z: (\d+?) TEMPC: ([\d.]+?)°C""", line)
        print(line, m, type(line)) # added for debug
        ....

... и это распечатано:

TEST001 sample     1/00001: X: 1 Y: 1 Z: 1 TEMPC: 25.95°C
 None <class 'str'>

... это то, что я использовал в приведенном выше примере.


И мой действительный рабочий скрипт, и мой файл со строками данных имеют окончания строк Unix (\n, то есть LF) - и я попытался смоделировать это выше test.py, также имея его с простыми окончаниями строк Unix.

У кого-нибудь есть идея, почему мой реальный рабочий скрипт читает файл построчно- ошибка строки (то есть результат re.search равен None) при синтаксическом анализе точно такой же строки, которая проходит более-менее без проблем в test.py, как показано в приведенных выше фрагментах?

Ответы [ 2 ]

1 голос
/ 30 сентября 2019

ОК, думаю, я понял это - давайте сначала проведем этот тест: сначала создадим текстовый файл, test.txt, Unix (только LF) окончания строк:

TEST001 sample     1/00001: X: 1 Y: 1 Z: 1 TEMPC: 25.95°C
TEST002 sample     1/00002: X: 1 Y: 1 Z: 1 TEMPC: 25.95°C
TEST003 sample     1/00003: X: 1 Y: 1 Z: 1 TEMPC: 25.95°C

Затем давайте попробуемэтот скрипт, test2.py:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import sys,os
import re

with open('test.txt', 'rt') as thelogfile:
  for line in thelogfile:
    if "something" in line: pass
    elif line.startswith("TEST001 sample"):
      m = re.search(r"""X: (\d+?) Y: (\d+?) Z: (\d+?) TEMPC: ([\d.]+?)°C""", line)
      print(line, m, type(line)) # added for debug

Теперь, если я запусту этот скрипт в Python 3 оболочки MINGW64 (так, /mingw64/bin/python3):

user@PC MINGW64 /tmp
$ python3 test2.py
TEST001 sample     1/00001: X: 1 Y: 1 Z: 1 TEMPC: 25.95°C
 None <class 'str'>

Итак, сноваматч не удался. Теперь давайте попробуем отладить с помощью pdb:

user@PC MINGW64 /tmp
$ python3 -m pdb test2.py
> c:/msys64/tmp/test2.py(4)<module>()
-> import sys,os
(Pdb) b 11
Breakpoint 1 at c:/msys64/tmp/test2.py:11
(Pdb) r
> c:/msys64/tmp/test2.py(11)<module>()
-> m = re.search(r"""X: (\d+?) Y: (\d+?) Z: (\d+?) TEMPC: ([\d.]+?)▒C""", line)
(Pdb) p line
'TEST001 sample     1/00001: X: 1 Y: 1 Z: 1 TEMPC: 25.95°C\n'
(Pdb) n
> c:/msys64/tmp/test2.py(12)<module>()
-> print(line, m, type(line)) # added for debug
(Pdb) p m
None
(Pdb)

Хорошо, так что здесь мы определенно можем видеть, что это та же строка текста, что и в OP, и объект соответствия (возвращаемый из re.search)Нет, поэтому проблема по-прежнему присутствует.

Однако обратите внимание, что когда PDB выводит строку «m = re.search ...», знак степени поврежден:

▒C

... тогда как если я печатаю строку самостоятельно, знак градуса в порядке:

°C

Итак, подозревая, что это может иметь отношение к кодировкам, я попробовал это в pdb- во-первых, я скопировал и вставил строку, которая выгружала pdb, со сломанным знаком степени:

(Pdb) re.search(r"""X: (\d+?) Y: (\d+?) Z: (\d+?) TEMPC: ([\d.]+?)▒C""", line)
(Pdb)

Очевидно, что в этом случае возврата нет. Затем я попытался запустить то же самое, за исключением того, что я скопировал и вставил строку re.search непосредственно из исходного файла в терминал:

(Pdb) re.search(r"""X: (\d+?) Y: (\d+?) Z: (\d+?) TEMPC: ([\d.]+?)°C""", line)
<re.Match object; span=(28, 58), match='X: 1 Y: 1 Z: 1 TEMPC: 25.95°C'>

Хорошо, так что здесь мы получили совпадение!

Таким образом, даже если этот вид подразумевает, что кодировка файла кода source не совсем верна - я обнаружил http://python -notes.curiousefficiency.org / en / latest / python3/text_file_processing.html и увидел аргумент encoding для open(), поэтому попытался использовать его с файлом data , - и это единственное изменение, которое мне нужно было сделать свыше test2.py:

with open('test.txt', 'rt', encoding='utf-8') as thelogfile:

... и, наконец, он начал работать:

user@PC MINGW64 /tmp
$ python3 test2.py
TEST001 sample     1/00001: X: 1 Y: 1 Z: 1 TEMPC: 25.95▒C
 <re.Match object; span=(28, 57), match='X: 1 Y: 1 Z: 1 TEMPC: 25.95▒C'> <class 'str'>

Почему это происходит, особенно для Python3 в оболочке MINGW64 (и почему он до сих порпроблема печати правильного UTF-8 в оболочку, где в противном случае Python3 оболочки MSYS2 не имеет проблем с этим), я не могу сказать - но, по крайней мере, я могу преодолеть пустую проблему возврата соответствия регулярному выражению, явно используя encoding='utf-8' при открытиифайл данных.

1 голос
/ 30 сентября 2019

Я предполагаю, что одна или несколько строк во входном файле, , а не строка, которую вы тестировали выше, не соответствуют ожидаемому шаблону. Вот предлагаемый сценарий, который вы можете попытаться очистить от таких несоответствующих строк:

filepath = 'your_input.csv'
with open(filepath) as fp:
    line = fp.readline()
    cnt = 1
    while line:
        m = re.search(r"""X: (\d+?) Y: (\d+?) Z: (\d+?) TEMPC: ([\d.]+?)°C""", line)
        if not m:
            print("Line #" + str(cnt) + " has a problem: " + line)
        line = fp.readline()
        cnt += 1

Предполагая, что есть только несколько ошибочных строк, вы можете отредактировать файл вручную и исправить данные.

...