Итак, я пытаюсь сделать кодировщик/декодер азбуки Морзе; Я сделал кодировщик, но декодер доставляет мне некоторые проблемы.
Итак, если я использую функциональный тест и ввожу «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?
. и - — специальные символы в регулярном выражении. Если вы пытаетесь сопоставить их буквально, вам нужно убежать от них.
@Mohamed Mufeed, так есть ли другая функция PHP, которая может искать группы точек и тире, чтобы заменить их? Обновлено: или каковы некоторые символы, которые НЕ являются специальными символами в регулярном выражении и немного редки?
Специальный символ @Crimin4L не означает, что вы не можете сопоставить их. Ты можешь. Но вам нужно избежать их, например. . становится \., а - становится \-
Также я гуглил, кажется, что ваша версия азбуки Морзе кажется неправильной, потому что согласно википедии вам нужен один пробел между каждой буквой.|- В той же букве три пробела между каждой буквой и 7 пробелов между каждым словом, какова ваша версия? не вижу пробелов
Я имею в виду, как вы разделяете слова и буквы?
Буквы разделяются пробелами (""), а слова разделяются пробелом-косой чертой-пробелом ("/"). Кажется, что каждый другой веб-сайт использует другой формат, я выбрал этот формат с этого веб-сайта: morsecode.world/international/translator.html






Обновлять
Если все ваши символы окружены пробелами (или началом/концом строки), вам, вероятно, будет проще использовать strtr, а не подход, основанный на регулярных выражениях. Поскольку strtr сначала заменяет самые длинные совпадения, вам не нужно беспокоиться о (например) частичной замене -.- (k) на -a.
function morsedecode($code){
$search = array('.-', '-...');
$replace = array('a', 'b');
return strtr($code, array_combine($search, $replace));
}
echo morsedecode(".- -...");
Выход:
a b
Оригинальный ответ
Ваша проблема в том, что \b соответствует границе слова, то есть месту, где символ слева является символом слова (a-zA-Z0-9_), а символ справа не является символом слова (или наоборот). Поскольку во входной строке нет символов слова, вы никогда не сможете сопоставить границу слова. Вместо этого вы можете использовать обходные пути для символа, который не является точкой или тире:
function morsedecode($code){
$search = array('/(?<![.-])\.-(?![.-])/', '/(?<![.-])-\.\.\.(?![.-])/');
$replace = array('a', 'b');
return preg_replace($search, $replace, $code);
}
echo morsedecode(".- -...");
Выход
a b
Обратите внимание, что . является специальным символом в регулярном выражении (соответствует любому символу) и должен быть экранирован, иначе он будет соответствовать как -, так и ..
Наверное, это было бы проще, чем то, что я в итоге сделал. Но спасибо за отличный ответ, никогда не знал, что могу заменить вещи с помощью strstr: P См. Ниже, что я в итоге сделал.
Также забавно, что вы уже знали, с чем я боролся, используя str_replace (-.- (k) частично заменяется на -a), поэтому я вернулся к preg_replace, чтобы решить эту проблему, но ударился о другую стену, ха-ха. Цените свалку знаний, хотя <3
@ Crimin4L Crimin4L да, я несколько раз сталкивался с такой проблемой. strtr действительно полезен для случаев, когда вы хотите сопоставить короткие строки, которые также могут быть подстроками более длинных строк, которые вы также хотите сопоставить.
Только что обновил мой код, чтобы использовать функцию strstr и array_combine, упомянутую в вашем обновленном ответе, и позвольте мне сказать вам, работает как шарм; Так просто! Спасибо еще раз дружище :)
\b — это граница слова, которая может быть любой из следующих.
'/\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
@Ник, да, я думал об этом. Честно говоря, у него будут большие проблемы, если только он не разбивает строку на пробелы и не сравнивает максимально длинную строку азбуки Морзе с входными данными или не использует якоря ^ и $` и не сопоставляет всю строку.
В итоге я придумал собственное небольшое решение проблемы:
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 определенно является эффективным способом.
Это другой способ сделать это. Больно, но функционально :)
Вы сразу перешли к проблеме, не дав фактического описания проблемы.