Preg_replace не работает с группами символов

Итак, я пытаюсь сделать кодировщик/декодер азбуки Морзе; Я сделал кодировщик, но декодер доставляет мне некоторые проблемы.

Итак, если я использую функциональный тест и ввожу «ab», он возвращает «ab». Однако, если я ввожу «a b», он возвращает «c d» (как и должно быть, 100% работает)

function test($code){
    $search = array('/\ba\b/', '/\bb\b/');
    $replace = array('c', 'd');
    return preg_replace($search, $replace, $code);
}

НО, когда я использую функцию morsedecode и ввожу ".- -...", она ничего не делает и перенастраивает ".- -...".

function morsedecode($code){
    $search = array('/\b.-\b/', '/\b-...\b/');
    $replace = array('a', 'b');
    return preg_replace($search, $replace, $code);
}

Я застрял, потому что, похоже, он не работает с символами, как с буквами и словами. Кто-нибудь знает причину этого и есть ли способ обойти это в PHP?

Вы сразу перешли к проблеме, не дав фактического описания проблемы.

Tim Biegeleisen 23.12.2020 04:41
. и - — специальные символы в регулярном выражении. Если вы пытаетесь сопоставить их буквально, вам нужно убежать от них.
Mohamed Mufeed 23.12.2020 04:43

@Mohamed Mufeed, так есть ли другая функция PHP, которая может искать группы точек и тире, чтобы заменить их? Обновлено: или каковы некоторые символы, которые НЕ являются специальными символами в регулярном выражении и немного редки?

Crimin4L 23.12.2020 04:52

Специальный символ @Crimin4L не означает, что вы не можете сопоставить их. Ты можешь. Но вам нужно избежать их, например. . становится \., а - становится \-

Mohamed Mufeed 23.12.2020 05:12

Также я гуглил, кажется, что ваша версия азбуки Морзе кажется неправильной, потому что согласно википедии вам нужен один пробел между каждой буквой.|- В той же букве три пробела между каждой буквой и 7 пробелов между каждым словом, какова ваша версия? не вижу пробелов

Mohamed Mufeed 23.12.2020 05:17

Я имею в виду, как вы разделяете слова и буквы?

Mohamed Mufeed 23.12.2020 05:24

Буквы разделяются пробелами (""), а слова разделяются пробелом-косой чертой-пробелом ("/"). Кажется, что каждый другой веб-сайт использует другой формат, я выбрал этот формат с этого веб-сайта: morsecode.world/international/translator.html

Crimin4L 23.12.2020 06:05
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
0
7
332
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Обновлять

Если все ваши символы окружены пробелами (или началом/концом строки), вам, вероятно, будет проще использовать strtr, а не подход, основанный на регулярных выражениях. Поскольку strtr сначала заменяет самые длинные совпадения, вам не нужно беспокоиться о (например) частичной замене -.- (k) на -a.

function morsedecode($code){
    $search = array('.-', '-...');
    $replace = array('a', 'b');
    return strtr($code, array_combine($search, $replace));
}

echo morsedecode(".- -...");

Выход:

a b

Демо на 3v4l.org

Оригинальный ответ

Ваша проблема в том, что \b соответствует границе слова, то есть месту, где символ слева является символом слова (a-zA-Z0-9_), а символ справа не является символом слова (или наоборот). Поскольку во входной строке нет символов слова, вы никогда не сможете сопоставить границу слова. Вместо этого вы можете использовать обходные пути для символа, который не является точкой или тире:

function morsedecode($code){
    $search = array('/(?<![.-])\.-(?![.-])/', '/(?<![.-])-\.\.\.(?![.-])/');
    $replace = array('a', 'b');
    return preg_replace($search, $replace, $code);
}

echo morsedecode(".- -...");

Выход

a b

Демо на 3v4l.org

Обратите внимание, что . является специальным символом в регулярном выражении (соответствует любому символу) и должен быть экранирован, иначе он будет соответствовать как -, так и ..

Наверное, это было бы проще, чем то, что я в итоге сделал. Но спасибо за отличный ответ, никогда не знал, что могу заменить вещи с помощью strstr: P См. Ниже, что я в итоге сделал.

Crimin4L 23.12.2020 05:57

Также забавно, что вы уже знали, с чем я боролся, используя str_replace (-.- (k) частично заменяется на -a), поэтому я вернулся к preg_replace, чтобы решить эту проблему, но ударился о другую стену, ха-ха. Цените свалку знаний, хотя <3

Crimin4L 23.12.2020 06:03

@ Crimin4L Crimin4L да, я несколько раз сталкивался с такой проблемой. strtr действительно полезен для случаев, когда вы хотите сопоставить короткие строки, которые также могут быть подстроками более длинных строк, которые вы также хотите сопоставить.

Nick 23.12.2020 07:01

Только что обновил мой код, чтобы использовать функцию strstr и array_combine, упомянутую в вашем обновленном ответе, и позвольте мне сказать вам, работает как шарм; Так просто! Спасибо еще раз дружище :)

Crimin4L 24.12.2020 08:20

\b — это граница слова, которая может быть любой из следующих.

  1. Перед первым символом в строке, если первый символ является символом слова.
  2. После последнего символа в строке, если последний символ является символом слова.
  3. Между двумя символами в строке, где один является символом слова, а другой не является символом слова.

'/\b.-\b/' Первый \b не совпадает в .- -... из-за #1. Конкретно if the first character is a word character

Символ слова = ASCII letter, digit or underscore, поэтому . не является символом слова.

Кроме того, вам нужно экранировать . символы, такие как \..

Попробуйте искать \s* (любое количество пробелов) вместо границы слова.

function morsedecode($code){
    $search = array('/\s*\.-\s*/', '/\s*-\.\.\.\s*/');
    $replace = array('a', 'b');
    return preg_replace($search, $replace, $code);
}

Пример https://regex101.com/r/LCZXCn/1

Это будет соответствовать -.-regex101.com/r/LCZXCn/2

Nick 23.12.2020 04:57

@Ник, да, я думал об этом. Честно говоря, у него будут большие проблемы, если только он не разбивает строку на пробелы и не сравнивает максимально длинную строку азбуки Морзе с входными данными или не использует якоря ^ и $` и не сопоставляет всю строку.

bassxzero 23.12.2020 05:01

В итоге я придумал собственное небольшое решение проблемы:

    function morsedecode($code){
        $bd_code = str_replace(array('.', '-', '/'), array('dot', 'dash', '~slash~'), $code);
        $search = array('/\bdotdash\b/', '/\bdashdotdotdot\b/', '/\bdashdotdashdot\b/', 'etc..');
        $replace = array('a', 'b', 'c', 'etc..');
        $string =  preg_replace($search, $replace, $bd_code);
        return str_replace(array(' ', '~slash~'), array('', ' '), $string);
    }

Определенно не самый эффективный, но выполняет свою работу. Ответ @Nick определенно является эффективным способом.

Это другой способ сделать это. Больно, но функционально :)

Nick 23.12.2020 07:01

Другие вопросы по теме