• Помогите составить регулярное выражение для замены первого вхождения слова в HTML, но строго вне анкоров и атрибутов?

    @dsd_corp
    Ну… У меня сейчас на примере из вопроса выделяет огурец в alt аттрибуте тега img: regexr.com?314li
    Сколько не пытайтесь, я вам все-равно придумаю контрпример. Ломать — не строить ))
    Кроме всего прочего в этой ветке я смотрю даже жадность(greedy) в регекспах не ограничивает никто )))
  • Помогите составить регулярное выражение для замены первого вхождения слова в HTML, но строго вне анкоров и атрибутов?

    @dsd_corp
    Вы так будете двигаться дальше бесонечно )))
    Вот ваш контрпример:
    <p>Самый <a><i>вкусный</i> огурец <b>корявый</b></a> рос ...
    
  • Помогите составить регулярное выражение для замены первого вхождения слова в HTML, но строго вне анкоров и атрибутов?

    @dsd_corp
    Да без проблем. Делайте с ним что хотите. Не забывайте только периодически в git поглядывать за обновлениями. Даже если вы будете полностью менять файл под себя, и обновления основной ветки вам не нужны, там все-равно могут появиться полезные для вас комментарии и правки найденных в последствии багов.
    Например на текущий момент парсер все-таки предназначен для работы в основном с более-менее логичными XML структурами, чем с бесбашенным HTML.

    Для XML не реализована обработка спецтегов типа CDATA.
    Предпарсер не обрабатывает в аттрибутах тегов(внутри кавычек) упомянутую выше ситуацию с символами <>.
    Все руки не доходят это доделать.

    Для HTML есть куча косяковых нюансов со вложенностью тегов, типа автоузнавания и автозакрытия некоторых последовательно идущих одинаковых:
    Как обрабатывать вложенные ссылки <a>? Оставлять вложенными или закрывать каждую, разбивая любую сложную ссылку на массив последовательных?
    Некоторые авторы пишут абзацы <p>, не закрывая эти теги, то есть вообще не используя </p>. На данный момент парсер их позакрывает сам, но сделает при этом в DOM-дереве вложенную елочку из этих тегов. А надо бы, чтобы перед каждым следующим абзацем предыдущий закрывался. И это только, если каждый новый открывающийся <p> идет на том же уровне, что и предыдущий. Иначе ведь бывает, что в абзаце внутри таблица, а в ней еще идет текст абзацами.
    Ну и т.п. Для HTML есть куча нюансов логической обработки структур и разных допущений, не относящихся к общему парсингу DOM.
  • Помогите составить регулярное выражение для замены первого вхождения слова в HTML, но строго вне анкоров и атрибутов?

    @dsd_corp
    Сам файл xmlp.inc давно тянет на отдельный пост, все вот время никак не выберу… парсер написан еще три года назад(в репозитории ссылку на хабрастатью видели наверно? в ней есть пруф о трех годах).

    Кстати, чтобы лучше понять, что мы получаем в этой DOM-оподобной структуре, и возможно применить этот парсер где угодно еще, можете внутри функции replace_text сразу после вызова xmlp_data2struct_with_offset вставить такую строчку:
    file_put_contents('./struct.txt', var_export($struct, true));
    

    После чего в выводном файле struct.txt уже рассматривать структуру в человеческом виде.
    Собственно структура будет состоять из двух частей. В $struct[0] будет сама DOM-структура, а в $struct[1] инфа о косяках и список их индексов.

    Например(кликнуть для просмотра)
    Пример части с ошибками:
      1 => 
      array (
        0 => 
        array (
          'description' => 'Unknown closing tags: 9',
          'data' => 
          array (
            55 => 56,
            58 => 59,
            62 => 65,
            66 => 67,
            69 => 70,
            71 => 72,
            50 => 111,
            119 => 122,
            123 => 124,
          ),
        ),
        1 => 
        array (
          'description' => 'Unclosed tags recovered: 4',
          'data' => 
          array (
            0 => 55,
            1 => 66,
            2 => 69,
            3 => 123,
          ),
        ),
      ), 
    

    Это лог ошибок с файла 276604.fb2, который есть в корне репозитория на ГитХабе.
    Здесь встреченных неизвестных(неожиданных) закрывающих тегов: 9
    Первый из этих девяти втречен в элементе 56 и закрыл собой элемент 55.
    Найти их по индексу можно в том же файле struct.txt, ища строку ['ind' => 55] (56-го элемента уже не найдете, т.к. закрывающие теги в результирующую древовидную структуру не входят).
    В исходном тексте это соответствует строке '<p>Анджей <a>Пилипюк</p>', где тег 55 это '<a>', а тег 56 это '</p>'.
    Эту же часть вы в struct.txt по индексам найдете как:
                        3 => 
                        array (
                          'ind' => 54,
                          'offset' => 1166,
                          'end_offset' => 1169,
                          'length' => 3,
                          'name' => 'p',
                          'lname' => 'p',
                          'known' => 1,
                          'type' => 1,
                          'content' => 
                          array (
                            0 => 'Анджей ',
                            1 => 
                            array (
                              'ind' => 55,
                              'offset' => 1176,
                              'end_offset' => 1179,
                              'length' => 3,
                              'name' => 'a',
                              'lname' => 'a',
                              'known' => 1,
                              'type' => 1,
                              'content' => 
                              array (
                                0 => 'Пилипюк',
                              ),
                            ),
                          ),
                        ),
    

    Фактически это значит, что есть тег [id#54 <p>], который в себе содержит('content' =>) два элемента:
    1. строка 'Анджей ';
    2. тег [id#55 <a>], содержащий в себе('content' =>) один элемент: строку 'Пилипюк'.

    Неожиданный тег [id#56 </p>] (неожиданный, потому что текущим открытым был [id#55 <a>]) закрыл оба предыдущих тега: незакрытый [id#55 <a>] и свой «родной» [id#54 <p>].

    Так произошло потому, что парсер при встрече такого неожиданного тега пытается откатиться по стеку назад и закрыть ближайший подходящий(с тем же именем), попутно закрывая остальные открытые.
    Таким образом, к примеру, строка:
    <p>Анджей <a>Пилипюк шел <b>по улице, насвистывая <i>незатейливую мелодию</p>
    
    превратится в результате в:
    <p>Анджей <a>Пилипюк шел <b>по улице, насвистывая <i>незатейливую мелодию</i></b></a></p>
    


    Собственно, этот же незакрытый тег [id#55 <a>], закрывшийся автоматически, мы встречаем первым в следующем разделе ошибок 'Unclosed tags recovered: 4'.

    Вот как-то так.
  • Помогите составить регулярное выражение для замены первого вхождения слова в HTML, но строго вне анкоров и атрибутов?

    @dsd_corp
    P.S. Ах да, там 1251 кодировка, если у вас система не винда, конвертните example.php и .txt-шники перед использованием.
  • Помогите составить регулярное выражение для замены первого вхождения слова в HTML, но строго вне анкоров и атрибутов?

    @dsd_corp
    smartup, у меня есть решение конкретно этой задачи(ради интереса собрал). Но не одной регуляркой(хотя они там частично юзаются). Кода довольно много, используется модуль парсера, но работает гибко, достаточно быстро и не грохается при косяках, в отличии от сишных XML парсеров, встроенных в PHP.
    Если автор попросит(если ему подойдет решение не на одной «волшебной» регулярке), то конечно вывалю, не вопрос.
  • Помогите составить регулярное выражение для замены первого вхождения слова в HTML, но строго вне анкоров и атрибутов?

    @dsd_corp
    Вам правильно заявляли. Такие задачи простыми регулярками не решаются.
    Поробуйте вставить слово «огурец» в тексте во все возможные валидные места.
    При данной товарищем Jaguar_ko регулярке она не сработает на слово «огурец» фактически до знака вопроса в вашем текстовом примере(да закрывающего тега A все выпадает автоматически).
    То есть фактически данная регулярка притянута к конкретному текстовому примеру, а не к вашему набору условий.
    Даже если ее попытаться допилить, с высокой вероятностью все-равно найдутся валидные ситуации, на которых она не сработает, либо невалидные, на которых сработает.
  • Как строить асинхронное приложение?

    @dsd_corp
    Многое в этом мире на что-нибудь похоже )
    Тут как бы не совсем один объект, имеющий много свойств.
    У каждого элемента интерфейса свой объект, работающий с одним запросом в один момент времени. Даже не объект — просто структура(не нужно объекты плодить для таких вещей — лишнее это).
    Если хотите, в эту же структуру можно помещать ссылку на callback, чтобы элемент интерфейса не опрашивал эту структуру постоянно, а только по реальным событиям.

    И все эти структуры просто объединены в одну общую структуру для удобства.
    Можете вообще сделать массив таких структур-запросов, не привязанных к конкретному элементу интерфейса.
    То есть элемент интерфейса просто регистрирует у контроллера коммуникаций запрос, получая назад его(запроса) ID. И далее по этому ID может запрашивать у этого же контроллера статус запроса, либо ловить callback, указанный при регистрации, а по ID можно например отменить запрос или отказаться от приема результата и callback'a. Таким образом, один и тот же элемент интерфейса может зарегистрировать и более одного запроса, а можно реализовать и регистрацию серии запросов и получить callback уже после приема всех данных.
    Естественно, при многопоточной работе не забывая о синхронизации вызовов.

    Так что конкретная реализация зависит исключительно от ваших потребностей и фантазии)
  • Как строить асинхронное приложение?

    @dsd_corp
    Вместо bool received; в таком случае лучше ввести поле состояния uint8 state;
    В нем может быть и received, и canceled и прочее.
    В таком случае при canceled вы можете в соответствующем блоке интерфейса не реагировать на клики, пока контроллер коммуникации не отменит действие и не грохнет эту структуру сам.
  • Как строить асинхронное приложение?

    @dsd_corp
    P.S. по поводу асинхронных отказов действия(cancel) и прочего из предыдущей ветки ответов то же самое: добавьте в структуру данных соответствующее поле отказа, либо просто грохните структуру, и контроллер коммуникации сам поймет, что надо прервать действие по данному контексту.
  • Посоветуйте программу для чтения электронных книг на PC

    @dsd_corp
    BookShelf вот этот вы имеете в виду?
    Классная была программа на движке IE. В ней мелких косяков хватало, и форматов не много поддерживалось(fb2 и конвертация из текста и вордовых/RTF документов), но она была приятной.
  • Как запомнить все вхождения?

    @dsd_corp
    Ну сорри, поторопился, шаблончик можно и вынести в отдельную переменную:
    $pattern='[\s]+([a-z]+)(?:[\s]*?\=[\s]*?[\d]+)?';
    ...
    $r=preg_match_all('/целое('.$pattern.')+/is', $s, $matches, PREG_SET_ORDER, 0);
    ...
    $r=preg_match_all('/'.$pattern.'/is', $m[0], $rmatches, PREG_SET_ORDER, 0);
    

    На первом проходе нам скобки и совпадения в паттерне не важны — мы отбираем нулевое совпадение — то есть всю строку.