Хорошо, я работаю с этими ENDF
данными, см. здесь. Иногда в файлах присутствует, пожалуй, самая раздражающая кодировка чисел с плавающей запятой в научной записи, которую я когда-либо видел1. Там часто употребляется, что вместо 1.234e-3
будет что-то вроде 1.234-3
(без «е»).
Теперь я видел библиотеку, которая просто меняет -
на e-
или +
на e+
простой заменой. Но это не работает, когда некоторые числа могут быть отрицательными. В конечном итоге вы получаете какую-то ерунду, например, e-5.122e-5
, когда на входе было -5.122-5
.
Итак, я думаю, мне нужно перейти к регулярному выражению? Я открыт для другого решения, более простого, но это лучшее, что я могу сейчас придумать. Я использую библиотеку re
Python. Я могу сделать простую замену, ищу [0-9]-[0-9]
и заменяю ее следующим образом:
import re
str1='-5.634-5'
x = re.sub('[0-9]-[0-9]','4e-5',str1)
print(x)
Но, очевидно, в целом это не сработает, потому что мне нужно, чтобы цифры до и после -
были такими, какими они были, а не просто тем, что я придумал... Раньше я использовал группы захвата, но это было бы самым быстрым способом в этот контекст, чтобы использовать группу захвата для цифр до и после -
и передать ее обратно в замену с помощью библиотеки регулярных выражений Python
import re
?
1 Да, я знаю, фортран... 80 символов... экономия места... перфокарты... уже никого не волнует.
Если вы хотите знать, что быстрее, просто измерьте их (т. е. засеките время).
...80 символов... уже никого не волнует. - Вы серьезно думаете, что пластинки фиксированной длины остались в прошлом?
Существует пакет pip под названием endf, который, вероятно, подойдет для ваших целей.
@Woodford Я думаю, что они осуждают отсутствие при сохранении символов подразумеваемой e в 1.234-5
, чтобы помочь соблюдать ограничение в 80 символов, а не записи фиксированной длины.
Вероятно, для этого не будет использоваться регулярное выражение, когда должны работать некоторые простые строковые операции:
s.replace("-", "e-").replace("+", "e+").lstrip("e")
Я бы пошел на что-нибудь в этом направлении - что заставляет меня чувствовать себя некомфортно, так это то, что это не будет работать напрямую для чисел с положительным показателем - но я понимаю, что это может сработать для OP . И затем, что-то, что можно сразу поймать [+-]
, мы уже находимся в области регулярных выражений. (в мои более сварливые дни, когда я был антиреэкспериментатором, я бы не прочь вылечить двоих .replace
, просто чтобы избежать и этого)
Это не будет работать с положительными показателями.
@dawg легко исправить ..
Использование разделения строк или прямой замены может решить эту проблему.
Но регулярное выражение с использованием метода re.sub
Python также может позаботиться об этом в одной строке, охватывая все крайние случаи (ведущий сигнал и т. д.):
import re
str1='-5.634-5'
num = float(re.sub(r"([0-9\-+.][0-9.]*)([\-+])(\d+)", r"\1e\2\3", str1))
print(num)
читается как: первый символ может быть +-. или цифра, за которой следует последовательность цифр или ., затем сигнал, обозначающий показатель степени, затем несколько цифр показателя степени. Просто добавьте «е» в среднюю группу — и пока мы этим занимаемся, сразу преобразуйте ее в «float», чтобы избавиться от возможного лидирующего «+» :-)
это отлично и полезно для улучшения моей игры с регулярными выражениями, спасибо! Принял другой ответ исключительно из соображений целесообразности этой ситуации.
Я бы сделал что-нибудь в этом духе.
Вы можете одновременно проверить, что число соответствует ожидаемому формату, и зафиксировать составные части с помощью регулярного выражения:
import re
cases=['-5.634-5','1.234-3','1.234+3','-1.234+3','1+2','-1-2']
for s in cases:
if m:=re.search(r'^([+-]?\d+(?:\.\d*)?)([+-]\d+)$', s):
f=float(f'{m.group(1)}e{m.group(2)}')
print('{0!r:10}\t=>\t{1}'.format(s, f))
else:
continue
# not a good number
Распечатки:
'-5.634-5' => -5.634e-05
'1.234-3' => 0.001234
'1.234+3' => 1234.0
'-1.234+3' => -1234.0
'1+2' => 100.0
'-1-2' => -0.01
Вы можете сопоставить заменяемый пробел с e
, указав, что ему не предшествует начало строки, а за ним следует -
или +
:
import re
str1='-5.634-5'
print(re.sub('(?<!^)(?=[-+])', 'e', str1))
Это выводит:
-5.634e-5
круто, спасибо за эти знания! принял более короткий ответ, но он, вероятно, более элегантен для обобщенного парсера.
Работает ли у вас утверждение ретроспективного просмотра?
re.sub('(?<=[0-9])-','e-',str1)