a123123 Posted August 10, 2011 Share Posted August 10, 2011 Hello. Lets find some random string that I need to replace, ex. # ab . cd $. And I want to change # to 3 and $ to 4 only if it is in this form of string. I write rexexp pattern: '/#(.*)(.)(.*)($)/' and replacement: 3 but why the whole string is replaced to 3, not only #? How can I change my string to 3 ab . cd $? Quote Link to comment Share on other sites More sharing options...
.josh Posted August 10, 2011 Share Posted August 10, 2011 You're going to have to try a lot harder to explain what you want...your post makes no sense. Quote Link to comment Share on other sites More sharing options...
a123123 Posted August 10, 2011 Author Share Posted August 10, 2011 Hey. I need to replace one particular sign only if it is part of specified string. In this case it is: # ab . cd $ where ab, cd are any random string, and there is dot which divides them. So if I had a string # abcd, without dot and $, it should not change. But if it is like # ab . cd $ # changes into 3. This what I got was changing the whole string to 3, but I need 3 ab . cd $ - how can I do it? Quote Link to comment Share on other sites More sharing options...
.josh Posted August 10, 2011 Share Posted August 10, 2011 $string = preg_replace('~#(.*?\..*?\$)~', '3\1', $string); Quote Link to comment Share on other sites More sharing options...
DavidAM Posted August 10, 2011 Share Posted August 10, 2011 You really need to show the code you are using to do the replacement. I suspect it is the replacement part that you have not coded correctly. By the way, I am not an expert at regular expressions, but that regexp will match your example string, it will also match stuff that does not fit your stated requirements. '/#(.*)(.)(.*)($)/' says: string starts with a literal "#" any number of any character (including NO characters at all) any single character any number of any character (including NO characters at all) a literal "$" I would think something like this would do it: '/#(.+\..+$)/' Quote Link to comment Share on other sites More sharing options...
.josh Posted August 10, 2011 Share Posted August 10, 2011 @DavidAM $ has special meaning in regex, it needs to be escaped too. Quote Link to comment Share on other sites More sharing options...
DavidAM Posted August 10, 2011 Share Posted August 10, 2011 Is it always special? Or only when it is at the end of the expression? I started to escape it, which would not hurt if it didn't need it, but then I didn't. Quote Link to comment Share on other sites More sharing options...
a123123 Posted August 10, 2011 Author Share Posted August 10, 2011 Thanks for all the answers. The code I am using is: <?php $patterns = array('/(?<!e)abcd/'); $replacements = array('abcde'); $string=$_POST['link']; echo preg_replace($patterns, $replacements, $string); ?> and when I have negation on the beginning of the string, it is good, becaise when I have string ex. habcd, it changes to habcde, and h is remaining. But if I place it on the end of the string, ex. abcd(?<!e), string like abcdh changes to abcde, while I need abcdeh (h not disappearing). I hope that it will be more clear now. What is ~ and ? for in this code? $string = preg_replace('~#(.*?\..*?\$)~', '3\1', $string); and what is for + here? '/#(.+\..+$)/' Quote Link to comment Share on other sites More sharing options...
.josh Posted August 10, 2011 Share Posted August 10, 2011 Is it always special? Or only when it is at the end of the expression? I started to escape it, which would not hurt if it didn't need it, but then I didn't. Yes, it is a special character, regardless of where it is in the pattern..it's just that you usually only see it at the end of the pattern because usually it doesn't make sense to use it elsewhere. But it also comes up a lot if you are combining it with alternations, or with multi-line mode. Only place that it is treated literally is inside a character class. http://www.php.net/manual/en/regexp.reference.meta.php Quote Link to comment Share on other sites More sharing options...
DavidAM Posted August 10, 2011 Share Posted August 10, 2011 I don't see any relationship between that pattern: '/(?<!e)abcd/' and your original post. Maybe we need to talk about what you are trying to do. Moving the negative look-behind to the end: abcd(?<!e) does not seem right. They way I read that, it says "find the letters 'abc' followed immediately by a 'd' that does not have an 'e' before it -- well, the pattern says to find 'abcd' so there is no way that an 'e' will be before the 'd'. -- I may be way off here, the assertions still confuse me a bit. I'm going to defer to the RegExperts here, cause I am really out of my depth. What is ~ and ? for in this code? $string = preg_replace('~#(.*?\..*?\$)~', '3\1', $string); The '~' is just the delimiter used for the expression. Your examples use a slash ('/'). Pretty much any character can be used. I personally usually use a tilde ('~') since I rarely will be searching for them. The '?' makes the '*' "less greedy" so it will not eat up the period ('.') that follows. A '.*' will match anything, and regexp's usually try to find the longest possible match, using the '?' says to find the shortest possible match considering the next character in the expression to be found. The '+' says to find one or more of the preceding character (in this case a '.' which says ANY character). Using '.*' will match zero or more characters. @Crayon Violent - O.K. thanks. I will make note of that and always escape the '$' inside an expression. I really need to study the assertions and alternations more. Quote Link to comment Share on other sites More sharing options...
a123123 Posted August 10, 2011 Author Share Posted August 10, 2011 I don't see any relationship between that pattern: '/(?<!e)abcd/' and your original post. Maybe we need to talk about what you are trying to do. Moving the negative look-behind to the end: abcd(?<!e) does not seem right. They way I read that, it says "find the letters 'abc' followed immediately by a 'd' that does not have an 'e' before it -- well, the pattern says to find 'abcd' so there is no way that an 'e' will be before the 'd'. -- I may be way off here, the assertions still confuse me a bit. I'm going to defer to the RegExperts here, cause I am really out of my depth. Thanks for the name "negative lookbehind". I concluded that in this case it must be something like "look forward", I found "look ahead" and it is much more clear now. I am going to try to do this and I will ask if I get problems. Thank you very much. All that I needed was "positive lookahead". The code that worked for me was: '/\#(?=.*?\..*?$)/' Quote Link to comment Share on other sites More sharing options...
a123123 Posted August 10, 2011 Author Share Posted August 10, 2011 Sorry for double post, but I have a last question about this thing. Now look behind: '/(?<=#.*?\..*?)\$/' and says it has no fixed length - where is it wrong? thanks Quote Link to comment Share on other sites More sharing options...
.josh Posted August 10, 2011 Share Posted August 10, 2011 Lookbehind has to have a fixed length pattern to match, so you cannot use quantifiers in a lookbehind. Example: abc is a fixed length; it has exactly 3 characters. .* is not a fixed length, because it can be 0 or more characters. As DavidAM mentioned... your followup posted code and what you are saying doesn't match what it is you previously said... so as I said in the beginning, you need to try harder to be a lot more clear in what you are trying to do. Give several examples of real input and what you want the results to look like. Quote Link to comment Share on other sites More sharing options...
a123123 Posted August 12, 2011 Author Share Posted August 12, 2011 Okay, sorry. I want to change every string like: # ab . cd $ to 3 ab . cd 4, example lets find some random strings: # 123 . abc $ # 456 . asd $ # 147 . qwe $ # 123 . zxc $ 123 # and I want to change #->3 and $->4 only in strings which are this form. String 123 # shouldn't be changed. The result should be: 3 123 . abc 4 3 456 . asd 4 3 147 . qwe 4 3 123 . zxc 4 123 # I solved problem #->3 with positive lookahead, and if positive lookbehind could be various length, it would be solved also for $->4. Any other ideas? Quote Link to comment Share on other sites More sharing options...
.josh Posted August 12, 2011 Share Posted August 12, 2011 you don't need lookaheads or lookbehinds, it's overkill...unless you are still not explaining the full context of the problem. $string = "# 147 . qwe $"; $string = preg_replace('~#(.*?\..*?)\$~', '3${1}4', $string); Quote Link to comment Share on other sites More sharing options...
a123123 Posted August 12, 2011 Author Share Posted August 12, 2011 Thanks for answer and help. I'm sorry, but I cant understand what more could I explain, may I ask for asking more specific question? What is ${1} for? Is it repetition of the same element? Quote Link to comment Share on other sites More sharing options...
.josh Posted August 12, 2011 Share Posted August 12, 2011 Thanks for answer and help. I'm sorry, but I cant understand what more could I explain, may I ask for asking more specific question? I think you are missing the point... unless there's other stuff you aren't mentioning, the lookahead/behind assertions are overkill, not necessary. Does the code I just posted work for you? What is ${1} for? Is it repetition of the same element? $1 is the first captured group in the pattern. ${1} is the same thing, but the {..} specifically tells php to look at $1 because you want to use that "4" afterwards, so it's there to keep it from being confused and try to use $14 (the 14th captured group - which doesn't exist). Quote Link to comment Share on other sites More sharing options...
a123123 Posted August 12, 2011 Author Share Posted August 12, 2011 quickly and helpful answer, thanks this is the only thing which I need to do, and this grouping looks nice. It works for me. I am a bit unexperienced in regexp, and I can do many unnecessary things. I liked these forums. You are really helpful. It was all what I needed, and there is no other point what I am missing Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.