Решение Perl
Это результат упрощенных изменений, которые я предложил для скрипта @ jkerian: используйте оператор flipflop и -p
.Я также исправил его регулярные выражения для использования правильных $1
и $2
в RHS, изменив разделители с s///
до s:::
, чтобы избежать LTS («Синдром наклоняющейся зубочистки») , идобавлено /x
для улучшения читабельности.В работе с жирным шрифтом и курсивом произошла логическая ошибка, которую я исправил.Я добавил комментарии, показывающие, каким должно быть преобразование в каждом случае, соответствующее исходному описанию проблемы, и выровнял RHS преобразований, чтобы их было легче читать.
#!/usr/bin/perl -p
#
# the -p option makes this a pass-through filter
#####################################################
# omit protected region
next if /^#\+BEGIN_EXAMPLE/ .. /^#\+END_EXAMPLE/;
# `some text` ⇒ =some text=
s: ` ( [^`]* ) ` :=$1=:gx;
# [desc](link) ⇒ [[link][desc]]
s: \[ ( [^]]* ) \] \( ( [^)]* ) \) :[[$2][$1]]:gx;
# ^## some heading ⇒ ** some heading
# NB: can't use /x here or would have to use ugly \#
s:^##:**:;
# *some italics* ⇒ /some italics/
s: (?!< \* ) \* ( [^*]+ ) \* (?! \*) :/$1/:gx;
# **some bold** ⇒ *some bold*
s: \*{2} ( [^*]+ ) \*{2} :*$1*:gx;
Видите, как это просто?Всего 6 простых строк в высшей степени читабельного кода на Perl.Это легко сделать в Perl, потому что Perl специально разработан для того, чтобы сделать написание такого фильтра очень простым, а Python - нет.У Python есть разные цели проектирования.
Хотя вы, конечно, можете переписать это на Python, это не стоило бы беспокоиться, потому что Python просто не предназначен для такого рода вещей.В Python отсутствует флаг -p
make-me-a-filter для неявного цикла и неявной печати.В Python отсутствует неявная переменная аккумулятора.В Python отсутствуют встроенные регулярные выражения.В Python отсутствует оператор s///
.А в Python отсутствует оператор триггера с сохранением состояния.Все это значительно упрощает чтение, запись и поддержку решения Perl, чем решение Python.
Однако вы не должны понимать, что это всегда так.Это не так.В других областях вы можете столкнуться с проблемами, которые Python предлагает в этих областях.Но не здесь.Это связано с тем, что этот фильтр является специализированной областью для Perl, а не для Python.
Следовательно, решение Python будет намного длиннее, шумнее и труднее для чтения - и, следовательно, сложнее в обслуживании - чемэто легкая версия Perl, все потому, что Perl был разработан, чтобы упростить задачу, и это одна из областей его целевого применения.Попробуйте переписать это на Python и обратите внимание, насколько это неприятно.Конечно, это возможно, но не стоит хлопот или технического обслуживания.
Версия Python
#!/usr/bin/env python3.2
from __future__ import print_function
import sys
import re
if (sys.version_info[0] == 2):
sys.stderr.write("%s: legacy Python detected! Please upgrade to v3+\n"
% sys.argv[0] )
##sys.exit(2)
if len(sys.argv) == 1:
sys.argv.append("/dev/stdin")
flip_rx = re.compile(r'^#\+BEGIN_EXAMPLE')
flop_rx = re.compile(r'^#\+END_EXAMPLE')
#EG# `some text` --> =some text=
lhs_backticks = re.compile(r'` ( [^`]* ) `', re.VERBOSE)
rhs_backticks = r'=\1='
#EG# [desc](link) --> [[link][desc]]
lhs_desclink = re.compile(r' \[ ( [^]]* ) \] \( ( [^)]* ) \) ', re.VERBOSE)
rhs_desclink = r'[[\2][\1]]'
#EG# ^## some heading --> ** some heading
lhs_header = re.compile(r'^##')
rhs_header = r'**'
#EG# *some italics* --> /some italics/
lhs_italics = re.compile(r' (?!< \* ) \* ( [^*]+ ) \* (?! \*) ', re.VERBOSE)
rhs_italics = r'/\1/'
## **some bold** --> *some bold*
lhs_bold = re.compile(r'\*{2} ( [^*]+ ) \*{2}', re.VERBOSE)
rhs_bold = r'*\1*'
errcnt = 0
flipflop = "flip"
for filename in sys.argv[1:]:
try:
filehandle = open(filename, "r")
except IOError as oops:
errcnt = errcnt + 1
sys.stderr.write("%s: can't open '%s' for reading: %s\n"
% ( sys.argv[0], filename, oops) )
else:
try:
for line in filehandle:
new_flipflop = None
if flipflop == "flip":
if flip_rx.search(line):
new_flipflop = "flop"
elif flipflop == "flop":
if flop_rx.search(line):
new_flipflop = "flip"
else:
raise FlipFlop_SNAFU
if flipflop != "flop":
line = lhs_backticks . sub ( rhs_backticks, line)
line = lhs_desclink . sub ( rhs_desclink, line)
line = lhs_header . sub ( rhs_header, line)
line = lhs_italics . sub ( rhs_italics, line)
line = lhs_bold . sub ( rhs_bold, line)
print(line, end="")
if new_flipflop != None:
flipflop = new_flipflop
except IOError as oops:
errcnt = errcnt + 1
sys.stderr.write("%s: can't read '%s': %s\n"
% ( sys.argv[0], filename, oops) )
finally:
try:
filehandle.close()
except IOError as oops:
errcnt = errcnt + 1
sys.stderr.write("%s: can't close '%s': %s\n"
% ( sys.argv[0], filename, oops) )
if errcnt == 0:
sys.exit(0)
else:
sys.exit(1)
Резюме
Важно использовать правильный инструмент для правильной работы,Для этой задачи этим инструментом является Perl, который занял всего 7 строк.Есть только 7 вещей, но не пытайтесь говорить об этом Python.Это как вернуться к ассемблеру со слишком большим количеством стеков прерываний.Python в 72 строки явно не подходит для такой работы, и вся сложная и шумная нечитаемость кода показывает, почему.Скорость ошибок на строку кода одинакова независимо от языка, поэтому, если у вас есть выбор между написанием N строк кода или 10 * N строк кода, выбора нет.