Jestem okropny z wyrażeniami regularnymi. Próbuję to zastąpić:
public static function camelize($word) {
return preg_replace('/(^|_)([a-z])/e', 'strtoupper("\\2")', $word);
}
z preg_replace_callback z funkcją anonimową. Nie rozumiem, co robi \\ 2. Albo o to, jak dokładnie działa preg_replace_callback.
Jaki byłby prawidłowy kod, aby to osiągnąć?
preg_replace_callback
. I\\2
zostanie$matches[2]
w wymienionym oddzwonieniu. A może konkretnie co do której części jesteś zdezorientowany?create_function
, to tylko kolejne opakowanieeval
. Powinieneś użyć odpowiedniej funkcji anonimowej, chyba że z jakiegoś powodu utkniesz w PHP 5.2.Odpowiedzi:
W wyrażeniu regularnym można „przechwycić” części dopasowanego ciągu za pomocą
(brackets)
; w tym przypadku przechwytujesz(^|_)
i([a-z])
części dopasowania. Są one numerowane począwszy od 1, więc masz odniesienia wsteczne 1 i 2. Dopasowanie 0 to cały dopasowany ciąg./e
Modyfikator pobiera ciąg zastępczy, a substytuty BACKSLASH następuje numer (np\1
) z odpowiednim odniesieniem wstecznego - ale dlatego, że jesteś w środku łańcucha, trzeba uciec backslash, więc masz'\\1'
. Następnie (skutecznie)eval
uruchamia wynikowy ciąg tak, jakby był to kod PHP (dlatego jest przestarzały, ponieważ jest łatwy w użyciueval
w niezabezpieczony sposób).preg_replace_callback
Funkcja zamiast wykonuje funkcję wywołania zwrotnego i przekazuje mu tablicę zawierającą dopasowane nawiązań wstecznych. Więc tam, gdzie byś napisał'\\1'
, zamiast tego uzyskujesz dostęp do elementu 1 tego parametru - np. Jeśli masz anonimową funkcję formularzafunction($matches) { ... }
, pierwsze odniesienie wsteczne znajduje się$matches[1]
wewnątrz tej funkcji.Więc
/e
argument'do_stuff(\\1) . "and" . do_stuff(\\2)'
może stać się oddzwonieniem do
function($m) { return do_stuff($m[1]) . "and" . do_stuff($m[2]); }
Albo w twoim przypadku
'strtoupper("\\2")'
może się stać
function($m) { return strtoupper($m[2]); }
Zauważ, że
$m
i$matches
nie są to magiczne nazwy, to tylko nazwa parametru, który podałem podczas deklarowania moich funkcji zwrotnych. Nie musisz też przekazywać funkcji anonimowej, może to być nazwa funkcji w postaci łańcucha lub coś w formiearray($object, $method)
, jak w przypadku każdego wywołania zwrotnego w PHP , np.function stuffy_callback($things) { return do_stuff($things[1]) . "and" . do_stuff($things[2]); } $foo = preg_replace_callback('/([a-z]+) and ([a-z]+)/', 'stuffy_callback', 'fish and chips');
Podobnie jak w przypadku każdej funkcji, domyślnie nie można uzyskać dostępu do zmiennych poza wywołaniem zwrotnym (z otaczającego zakresu). Korzystając z funkcji anonimowej, możesz użyć
use
słowa kluczowego, aby zaimportować zmienne, do których chcesz uzyskać dostęp, zgodnie z opisem w podręczniku PHP . np. jeśli stary argument był'do_stuff(\\1, $foo)'
wtedy może wyglądać nowe wywołanie zwrotne
function($m) use ($foo) { return do_stuff($m[1], $foo); }
Gotchas
preg_replace_callback
to zamiast z/e
modyfikatora na regex, więc trzeba usunąć tę flagę z „wzorcem” argument. Taki wzór/blah(.*)blah/mei
stałby się/blah(.*)blah/mi
./e
Modyfikator stosowany wariantaddslashes()
wewnętrznie na argumentach, więc niektóre zamienniki stosowanestripslashes()
, aby go usunąć; w większości przypadków prawdopodobnie będziesz chciał usunąć to połączeniestripslashes
z nowego wywołania zwrotnego.źródło
preg_replace shim z obsługą eval
To jest bardzo niewskazane. Ale jeśli nie jesteś programistą lub naprawdę wolisz okropny kod, możesz użyć
preg_replace
funkcji zastępczej, aby tymczasowo utrzymać/e
flagę w działaniu ./** * Can be used as a stopgap shim for preg_replace() calls with /e flag. * Is likely to fail for more complex string munging expressions. And * very obviously won't help with local-scope variable expressions. * * @license: CC-BY-*.*-comment-must-be-retained * @security: Provides `eval` support for replacement patterns. Which * poses troubles for user-supplied input when paired with overly * generic placeholders. This variant is only slightly stricter than * the C implementation, but still susceptible to varexpression, quote * breakouts and mundane exploits from unquoted capture placeholders. * @url: https://stackoverflow.com/q/15454220 */ function preg_replace_eval($pattern, $replacement, $subject, $limit=-1) { # strip /e flag $pattern = preg_replace('/(\W[a-df-z]*)e([a-df-z]*)$/i', '$1$2', $pattern); # warn about most blatant misuses at least if (preg_match('/\(\.[+*]/', $pattern)) { trigger_error("preg_replace_eval(): regex contains (.*) or (.+) placeholders, which easily causes security issues for unconstrained/user input in the replacement expression. Transform your code to use preg_replace_callback() with a sane replacement callback!"); } # run preg_replace with eval-callback return preg_replace_callback( $pattern, function ($matches) use ($replacement) { # substitute $1/$2/… with literals from $matches[] $repl = preg_replace_callback( '/(?<!\\\\)(?:[$]|\\\\)(\d+)/', function ($m) use ($matches) { if (!isset($matches[$m[1]])) { trigger_error("No capture group for '$m[0]' eval placeholder"); } return addcslashes($matches[$m[1]], '\"\'\`\$\\\0'); # additionally escapes '$' and backticks }, $replacement ); # run the replacement expression return eval("return $repl;"); }, $subject, $limit ); }
W istocie wystarczy dołączyć tę funkcję do swojej bazy kodu i edytować
preg_replace
jąpreg_replace_eval
tam, gdzie/e
została użyta flaga.Plusy i minusy :
preg_replace_callback
.Generator kodów zastępczych
Teraz jest to trochę zbędne. Ale może pomóc tym użytkownikom, którzy wciąż są przytłoczeni ręczną restrukturyzacją kodu do
preg_replace_callback
. Chociaż jest to bardziej czasochłonne, generator kodu ma mniej problemów z rozszerzeniem/e
zastępującego ciągu znaków na wyrażenie. To bardzo zwyczajne nawrócenie, ale prawdopodobnie wystarcza w przypadku większości rozpowszechnionych przykładów.Aby użyć tej funkcji, edytuj każde przerwane
preg_replace
wywołaniepreg_replace_eval_replacement
i uruchom je raz . Spowoduje to wydrukowanie odpowiedniegopreg_replace_callback
bloku, który ma zostać użyty w jego miejsce./** * Use once to generate a crude preg_replace_callback() substitution. Might often * require additional changes in the `return …;` expression. You'll also have to * refit the variable names for input/output obviously. * * >>> preg_replace_eval_replacement("/\w+/", 'strtopupper("$1")', $ignored); */ function preg_replace_eval_replacement($pattern, $replacement, $subjectvar="IGNORED") { $pattern = preg_replace('/(\W[a-df-z]*)e([a-df-z]*)$/i', '$1$2', $pattern); $replacement = preg_replace_callback('/[\'\"]?(?<!\\\\)(?:[$]|\\\\)(\d+)[\'\"]?/', function ($m) { return "\$m[{$m[1]}]"; }, $replacement); $ve = "var_export"; $bt = debug_backtrace(0, 1)[0]; print "<pre><code> #---------------------------------------------------- # replace preg_*() call in '$bt[file]' line $bt[line] with: #---------------------------------------------------- \$OUTPUT_VAR = preg_replace_callback( {$ve($pattern, TRUE)}, function (\$m) { return {$replacement}; }, \$YOUR_INPUT_VARIABLE_GOES_HERE ) #---------------------------------------------------- </code></pre>\n"; }
Pamiętaj, że samo kopiowanie i wklejanie nie jest programowaniem. Będziesz musiał dostosować wygenerowany kod z powrotem do rzeczywistych nazw zmiennych wejścia / wyjścia lub kontekstu użycia.
$OUTPUT =
przypisanie musiałoby przejść, gdyby poprzedniepreg_replace
wywołanie zostało użyte w plikuif
.A wyrażenie zastępcze może wymagać większej poprawy czytelności lub przeróbek.
stripslashes()
często staje się zbędne w wyrażeniach dosłownych.use
lubglobal
odniesienia do / w wywołaniu zwrotnym."-$1-$2"
odniesienia do przechwytywania zostaną podzielone składniowo przez zwykłą transformację do"-$m[1]-$m[2]
.Kod wyjściowy jest jedynie punktem wyjścia. I tak, byłoby to bardziej przydatne jako narzędzie online. To podejście do przepisywania kodu (edycja, uruchamianie, edycja, edycja) jest nieco niepraktyczne. Jednak może być bardziej przystępny dla tych, którzy są przyzwyczajeni do kodowania skoncentrowanego na zadaniach (więcej kroków, więcej odkryć). Ta alternatywa może więc ograniczyć kilka dodatkowych pytań.
źródło
Nie powinieneś używać flagi
e
(lubeval
ogólnie).Możesz także skorzystać z biblioteki T-Regx
pattern('(^|_)([a-z])')->replace($word)->by()->group(2)->callback('strtoupper');
źródło