PHP: how to convert this sentence in given format
"[5|f开发者_开发问答ive] [Tips|Suggestions] for an Unforgettable Trip|Five suggestions for a un-regret able Trip|[5|five] [tips|suggestions] for an [amazing|incredible] Trip|Five [tips|suggestions] for an astonishing Trip"
to
"[5|five] [Tips|Suggestions] for an Unforgettable Trip~Five suggestions for a un-regret able Trip~[5|five] [tips|suggestions] for an [amazing|incredible] Trip~Five [tips|suggestions] for an astonishing Trip"
I could use str_replace("|", "~", $code)
but the issue is I don't want to convert "|"
into "~"
if it is between "[ ]"
.
for($i=0,$s=strlen($str),$c=0;$i<$s;++$i){
if($str[$i]=='[')++$c;
elseif($str[$i]==']')--$c;
elseif(!$c && $str[$i]=='|')$str[$i]='~';
}
$in = "[5|five] [Tips|Suggestions] for an Unforgettable Trip|Five suggestions for a un-regret able Trip|[5|five] [tips|suggestions] for an [amazing|incredible] Trip|Five [tips|suggestions] for an astonishing Trip";
$out = preg_replace('/(?<=^|\])([^\[]*?)\|([^\[]*?)(?=\[|$)/s', '\1~\2', $in);
The regular expression works as follows, and will be correct as long as you don't nest brackets ([foo [bar]]
).
(?<=^|\])
- start at the beginning of the string or following a]
([^\[]*?)
- capture any number of characters that aren't a[
\|
- the character we want to replace
([^\[]*?)
- capture any number of characters that aren't a[
(again)
(?=\[|$)
- stop matching at the end of the string or before a[
This regex should do what you're after /^(?<!\[.)\|(?!].)/
Combine with preg_replace
and klabamo you've got it :)
This now seems to work a lot better!
$sentence = "[5|five] [Tips|Suggestions] for an Unforgettable Trip~Five suggestions for a un-regret able Trip~[5|five] [tips|suggestions] for an [amazing|incredible] Trip~Five [tips|suggestions] for an astonishing Trip";
$newSentence = preg_replace("/^(?<!\[.)\|(?!].)/", "~", $sentence);
echo $newSentence;
You can first replace all with str_replace and then re-replace those which are inside []
(Demo):
$subject = '[5|five] [Tips|Suggestions] for an Unforgettable Trip|Five suggestions for a
un-regret able Trip|[5|five] [tips|suggestions] for an [amazing|incredible] Trip|Five [tips|suggestions] for an astonishing Trip';
$result = str_replace('|', '~', $subject);
$pattern = '((\[[^\]]*)~([^\[]*\]))';
$result = preg_replace($pattern, '$1|$2', $result);
var_dump($subject, $result);
If you know the square brackets will always be properly balanced and never nested, a simple lookahead is all you need:
$after = preg_replace('/\|(?![^][]*+\])/', '~', $before);
demo
Starting immediately after the pipe character, the lookahead scans for the next right square bracket. If it finds one without seeing a left square bracket first, the pipe must be inside a pair of brackets. There's no need to check for the opening bracket with a lookbehind, which is good, because PHP (like most regex flavors) doesn't support variable-width lookbehinds.
I used a negative lookahead, but a positive lookahead could work, too:
$after = preg_replace('/\|(?=[^][]*+(?:\[|$))/', '~', $before);
demo
Note that it isn't necessary to escape the right square bracket in a character class if it's the first character listed (or, as in this case, the first character after the negating ^
). Thus, the odd-looking [^][]
for "not a square bracket". And *+
is a possessive quantifier.
If square brackets can be nested, you should forget about regexes and go with @RiaD's solution. It might still be possible to use regexes, but it will be a lot more complicated.
You could potentially use PHP preg_match and combine with str_replace - I am not a regexp expert so I won't be able to write anything for you.
http://php.net/manual/en/function.preg-match.php
精彩评论