Это регулярное выражение должно делать то, что вы хотите:
(^[^#]*#|(?<!^)\G)[^'\n]*\K'
Он ищет '
, которому предшествует либо
^[^#]*#
: начало строки и некоторые количество не #
символов, за которыми следует #
; или (?<!^)\G
: начало строки или конец предыдущего совпадения (\G
), с отрицательным взглядом на начало строки (?<!^)
, что означает, что оно совпадает только в конце предыдущее совпадение
, а затем некоторое количество не '
или символов новой строки (чтобы предотвратить совпадение совпадений вокруг конца предыдущей строки) символов [^'\n]*
.
Затем мы используем \K
для сброса совпадения, чтобы все, что до этого было отброшено из совпадения, а регулярное выражение соответствовало только '
.
, которое затем можно заменить на "
.
Демонстрация по регулярному выражению regex101
Обновление
Вы можете избежать совпадения апострофов в словах, сопоставляя только те из них, которые предшествуют или следуют без символ слова:
(^[^#]*#|(?<!^)\G)[^'\n]*\K('(?=\W)|(?<=\W)')
Демонстрация на regex101
Обновление 2
Вы также можете иметь дело со случаем, когда есть #
символов в строках, квалифицируя первую часть регулярного выражения с требованием t для заранее согласованных пар кавычек:
(?:^[^'#]*(?:'[^']*'[^#']*)*[^'#]*#|(?<!^)\G)[^'\n]*\K(?:'(?=\W)|(?<=\W)')
Демонстрация по регулярному выражению regex101