Я некоторое время пытался найти ответ на этот вопрос, но не смог его найти. Было много постов, связанных с соответствующим текстом, которому не предшествует определенный текст, но, похоже, ни один из них не работает в этом случае, где + соответствует, но это разрешено, только если ему предшествует один + (например, ++)
Я пытаюсь удалить знаки препинания из текста, но оставляю два последовательных знака ++, но одиночные + исчезают
$text="Hello World! C+ C++ C#";
print_r(preg_replace('/(?!\+\+)[[:punct:]]/', ' ', $text));
Результаты (я не уверен, почему последний + удален? Может кто-нибудь объяснить?):
Hello World C C + C
Если я попробую:
$text="Hello World! C+ C++ C#";
print_r(preg_replace('/(?!\+)[[:punct:]]/', ' ', $text));
Результат:
Hello World C + C ++ C
Но результат, который я хочу получить:
Hello World C C ++ C
Спасибо
ОБНОВЛЕНИЕ: я понял, что я должен упомянуть, что у меня будут другие персонажи, которых я хочу избежать. Возможно, я упростил вопрос. Например, я могу хотеть избежать # также, таким образом, результат будет
Hello World C C ++ C #
решение должно быть легко расширяемым. Я сожалею о неудобствах, вызванных этой недостающей информацией.
У вас есть несколько вариантов здесь, один из которых:
(?<!\+)[+#](?!\+)
# with lookarounds making sure no + is after/behind
Увидеть демо на regex101.com.
В PHP
:
<?php
$regex = '~(?<!\+)[+#](?!\+)~';
$string = 'Hello World! C+ C++ C#';
$string = preg_replace($regex, '', $string);
echo $string;
?>
Еще один будет использовать (*SKIP)(*FAIL)
механизм (который немного быстрее в этом примере):
\+{2}(*SKIP)(*FAIL)|[+#]
# let two consecutive ++ always fail
Посмотреть демо для этого на также regex101.com.
Последний, но тем не менее важный:
Если вы хотите добавить символы / выражения, которых также следует избегать, вы можете поместить их в группу без захвата и позволить этому произойти сбой:
(?:\#|\+{2})(*SKIP)(*FAIL)|
[[:punct:]]
Еще один демо на замечательном сайте regex101.com.
Ваше первое регулярное выражение (?!\+\+)[[:punct:]]
не работает, потому что он ищет два подряд +
знаки отрицания — в каждой позиции — затем утверждают, что следующим непосредственным символом является знак пунктуации. Когда он видит C++
курсор находится рядом с первым +
знак, этот матч успешно, так как нет +
после второго +
, Итак, сначала +
совпадает.
Hello World! C+ C+|+ C#
^ Cursor here - (?!\+\+)[[:punct:]] is matched
Regex:
[[:punct:]]++((?<=\+)(?<=[^+]\+))
Притяжательное совпадение в дополнение к условному положительному взгляду за утверждением сделает работу.
Объяснение:
[[:punct:]]++ // Match punctuation marks possessively - won't allow backtrack
((?<=\+) // Start of a conditional statement, check if last match is a `+`
(?<=[^+]\+) // If yes, it should not be preceded by another `+`
) // End of conditional
PHP:
preg_replace('@[[:punct:]]++((?<=\+)(?<=[^+]\+))@', ' ', $text)
Обновить
Если +
одиночкам всегда предшествуют некоторые буквы, есть гораздо более короткое решение:
\b\+(?!\+)
Первый фрагмент кода работает следующим образом: символ пунктуации найден, и если он не является отправной точкой для ++
последовательность, это сопоставлено и удалено. Итак, второе +
в C++
совпадает и удаляется.
Вы можете соответствовать и отказаться от матча с помощью (*SKIP)(*FAIL)
глаголы что вы хотите сохранить и просто сопоставить то, что вы хотите удалить:
preg_replace('/\+{2}(*SKIP)(*F)|[[:punct:]]+/', ' ', $text);
Добавление большего количества символов — на всякий случай:
preg_replace('/(?:[#^]|\*{3}|\+{2})(*SKIP)(*F)|[[:punct:]]+/', ' ', $text);
^^^ ^
Увидеть PHP демо
подробности:
\+{2}(*SKIP)(*FAIL)
— Матчи 2 +
символы, а затем сбрасывает их из матча|
— или же[[:punct:]]+
— соответствует одному или нескольким знакам препинания.В шаблоне замены мы просто заменяем пробелом.
Я думаю, что есть три случая, чтобы соответствовать плюсу.
Двойной плюс должен быть подобран, чтобы пройти мимо него.
Примечание. Это следует правилам слева направо о знаках плюса. Без правил, кроме этих.
Найти:
[^\P{P}+]|(\+\+)\+|\+
Заменить: '$1 '
Разъяснения
[^\P{P}+] # Punctuation but not plus
|
( \+\+ ) # (1), Plus with leading ++
\+
|
\+ # Any old plus sign
Который может быть уменьшен до
[^\P{P}+] # Punctuation but not plus
|
( \+\+ )? # (1), Plus with optional leading ++
\+