Dawno tu nie pisałem… No cóż, (bardzo) dużo pracy, życie osobiste i takie tam – to odstrasza od blogowania ;) Jeśli już, to od czasu do czasu coś publikuję jeśli chodzi o zdjęcia, a sprawy “kodowe” to raczej “robię” niż o nich piszę :)
Jako że od kilka dni jestem na L4, to się ostro opierdzielam, ale dopiero dziś jestem w stanie podjąć jakikolwiek intelektualny wysiłek… No to popatrzyłem sobie m.in. na GoldenLine. Dziś na forum PHPowym ktoś poruszył dość banalny problem, ktoś inny podrzucił rozwiązanie (preg_replace_callback (), a ja zacząłem się zastanawiać czemu wszyscy w PHP tak napierają na regexpy (rozumiem w Perlu, ale PHP?). Jak zacząłem się zastanawiać jak to zrobić bez regexpów, to zacząłem się bawić w zakodowanie tego ;)
Najpierw zrobiłem dość banalną wersję, przy użyciu strlen (), strpos () i substr (), i chciałem ją podać jako wersję hardcore ;) Wtedy pomyślałem sobie, że prawdziwa wersja hardcore, to byłaby bez użycia tychże funkcji… najprostsza postać tego to zastąpienie tychże funkcji swoimi ;) I o ile substr () i strpos () są dość banalne, o tyle dla mnie prawdziwym hardcorem jest strlen () ;)
Oczywiście nie są to najbardziej optymalne wydajne rozwiązania (a jeśli są to tylko przypadkiem), bo jeśli chodzi o optymalizację, to trzeba by używać wersji natywnych to trzeba by się najpierw zastanowić i sprawdzić czy jest co optymalizować… :) A całość warto potraktować stricte jako zabawę, którą dla mnie było pisanie tego :)
W całym “problemie” chodziło o zastąpienie w tekście wystąpień “[userId]ID[/userId]” tym, co zostanie wyplute przez dodatkową funkcję której podajemy zawartość tego co jest między znacznikami. Użycie preg_replace_callback () jest chyba najbardziej intuicyjnym rozwiązaniem, ale nie jedynym… :) Poniżej obydwie wersje: hardcore i bardziej hardcore – enjoy ;)
hardcore
function replace_user_id ($str, $fn) {
$tags = array ('start' => '[userId]', 'end' => '[/userId]');
$tag_len = array (
'start' => strlen ($tags['start']),
'end' => strlen ($tags['end'])
);
$offset = $pos_end = 0;
$ret = '';
$strlen = strlen ($str);
while ($pos_end < $strlen) {
if (
($pos_start = strpos ($str, $tags['start'], $pos_end)) !== false &&
($pos_end = strpos ($str, $tags['end'], $pos_start)) !== false
) {
$ret .= substr ($str, $offset, $pos_start - $offset);
$pos_start += $tag_len['start'];
$ret .= $fn (substr ($str, $pos_start, $pos_end - $pos_start));
$pos_end += $tag_len['end'];
$offset = $pos_end;
}
else {
break;
}
}
return $ret;
}
bardziej hardcore
class __mstrlen__ErrH {
private static $error = false;
private function __construct () {}
static public function errh ($errno, $errstr, $errfile = '', $errline = 0, $errctx = array ()) {
if ($errno != E_NOTICE) {
return false;
}
$expected = 'Uninitialized string offset';
for ($i=0; $i<26; ++$i) {
if ($expected[$i] != $errstr[$i]) {
return false;
}
}
self::$error = true;
}
public static function isError () {
return self::$error;
}
public static function zero () {
self::$error = false;
}
}
function mstrlen ($str) {
$str = (string) $str;
$len = -1;
__mstrlen__ErrH::zero ();
set_error_handler (array ('__mstrlen__ErrH', 'errh'), E_NOTICE);
while (__mstrlen__ErrH::isError () === false) {
++$len;
$q = $str[$len];
}
restore_error_handler ();
return $len < 0 ? 0 : $len;
}
function mstrpos ($str, $seek, $offset=0) {
if (!is_int ($offset) || $offset < 0) {
$offset = 0;
}
$str_len = mstrlen ($str);
if ($offset > $str_len) {
return false;
}
$seek_len = mstrlen ($seek);
for ($i=$offset; $i < $str_len; ++$i) {
for ($j=0; $j < $seek_len; ++$j) {
if ($str[$i + $j] != $seek[$j]) {
break;
}
}
if ($j == $seek_len) {
return $i;
}
}
return false;
}
function msubstr ($str, $start, $length = null) {
$str_len = mstrlen ($str);
if (!is_int ($start)) {
trigger_error ('Incorrect offset');
}
else if ($start >= $str_len) {
return false;
}
else if ($start < 0) {
$start = $str_len + $start;
}
if (!is_int ($length)) {
$length = $str_len - $start;
}
else if ($length < 0) {
$length = $str_len + $length - $start;
}
else if ($length + $start > $str_len) {
$length = $str_len - $start;
}
$ret = '';
for ($i=0; $i < $length; ++$i) {
$ret .= $str[$i + $start];
}
return $ret;
}
function replace_user_id2 ($str, $fn) {
$tags = array ('start' => '[userId]', 'end' => '[/userId]');
$tag_len = array (
'start' => mstrlen ($tags['start']),
'end' => mstrlen ($tags['end'])
);
$offset = $pos_end = 0;
$ret = '';
$strlen = mstrlen ($str);
while ($pos_end < $strlen) {
if (
($pos_start = mstrpos ($str, $tags['start'], $pos_end)) !== false &&
($pos_end = mstrpos ($str, $tags['end'], $pos_start)) !== false
) {
$ret .= msubstr ($str, $offset, $pos_start - $offset);
$pos_start += $tag_len['start'];
$ret .= $fn (msubstr ($str, $pos_start, $pos_end - $pos_start));
$pos_end += $tag_len['end'];
$offset = $pos_end;
}
else {
break;
}
}
return $ret;
}
