preg_match のキャプチャ - odz buffer
<?php
$words = explode(' ', 'abc ab ac');
foreach ($words as $word) {
preg_match('/\A (a) (b)? (c)? \z/x', $word, $match);
print_r($match);
}
?>
% php test.php
Array
(
[0] => abc
[1] => a
[2] => b
[3] => c
)
Array
(
[0] => ab
[1] => a
[2] => b
)
Array
(
[0] => ac
[1] => a
[2] =>
[3] => c
)
最後のキャプチャがない。null なり空文字なりが入るもんだと思っていたけど、こういうもの?
つーことでちとしらべてみますた。
まずは mb_eregで同じことを(ちょっと正規表現そのものの書き方は違いますが)。
<?php
foreach ($words as $word) {
mb_ereg('(?x)\A (a) (b)? (c)? \z', $word, $match);
print_r($match);
}
Array
(
[0] => abc
[1] => a
[2] => b
[3] => c
)
Array
(
[0] => ab
[1] => a
[2] => b
[3] =>
)
Array
(
[0] => ac
[1] => a
[2] =>
[3] => c
)
これはPerlのそれと同じと思われるので(二番目の例で配列要素が3まであり、
三番目の例では2が空)、preg_* のバグっぽいですね。
ということでちょっとソースを。
/* {{{ proto int preg_match(string pattern, string subject [, array subpatterns [, int flags [, int offset]]])
Perform a Perl-style regular expression match */
PHP_FUNCTION(preg_match)
{
php_pcre_match(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
}
/* }}} */
まず入り口。
/* {{{ php_pcre_match
*/
static void php_pcre_match(INTERNAL_FUNCTION_PARAMETERS, int global)
{
(ry
/* Execute the regular expression. */
count = pcre_exec(re, extra, subject, subject_len, start_offset,
exoptions|g_notempty, offsets, size_offsets);
/* Check for too many substrings condition. */
if (count == 0) {
zend_error(E_NOTICE, "Matched, but too many substrings");
count = size_offsets/3;
}
/* If something has matched */
if (count >= 0) {
ここで PCREの関数(pcre_exec)を呼び出す。
今回は関係ないのでcompileの方は省略。
前後しましたがpcre_execのプロトタイプや戻り値の意味は以下の通り。
Returns: > 0 => success; value is the number of elements filled in
= 0 => success, but offsets is not big enough
-1 => failed to match
< -1 => some kind of unexpected problem
*/
PCRE_DATA_SCOPE int
pcre_exec(const pcre *argument_re, const pcre_extra *extra_data,
PCRE_SPTR subject, int length, int start_offset, int options, int *offsets,
int offsetcount)
{
pcre_exec を呼び出した後の判定
/* If something has matched */
if (count >= 0) {
matched++;
match = subject + offsets[0];
/* If subpatterns array has been passed, fill it in with values. */
if (subpats != NULL) {
/* Try to get the list of substrings and display a warning if failed. */
if (pcre_get_substring_list(subject, offsets, count, &stringlist) < 0) {
efree(subpat_names);
efree(offsets);
efree(re);
zend_error(E_WARNING, "Get subpatterns list failed");
return;
}
pcre_get_substring_list で実際に捕獲した部分文字列をコピーしてきます。
結果は char** の stringlist に返ってきます。
if (global) { /* global pattern matching */
if (subpats_order == PREG_PATTERN_ORDER) {
/* For each subpattern, insert it into the appropriate array. */
for (i = 0; i < count; i++) {
if (offset_capture) {
add_offset_pair(match_sets[i], (char *)stringlist[i],
offsets[(i<<1)+1] - offsets[i<<1], offsets[i<<1], NULL);
} else {
add_next_index_stringl(match_sets[i], (char *)stringlist[i],
offsets[(i<<1)+1] - offsets[i<<1], 1);
}
}
/*
* If the number of captured subpatterns on this run is
* less than the total possible number, pad the result
* arrays with empty strings.
*/
if (count < num_subpats) {
for (; i < num_subpats; i++) {
add_next_index_string(match_sets[i], "", 1);
}
}
} else {
/* Allocate the result set array */
ALLOC_ZVAL(result_set);
array_init(result_set);
INIT_PZVAL(result_set);
/* Add all the subpatterns to it */
for (i = 0; i < count; i++) {
if (offset_capture) {
add_offset_pair(result_set, (char *)stringlist[i],
offsets[(i<<1)+1] - offsets[i<<1], offsets[i<<1], subpat_names[i]);
} else {
if (subpat_names[i]) {
add_assoc_stringl(result_set, subpat_names[i], (char *)stringlist[i],
offsets[(i<<1)+1] - offsets[i<<1], 1);
}
add_next_index_stringl(result_set, (char *)stringlist[i],
offsets[(i<<1)+1] - offsets[i<<1], 1);
}
}
/* And add it to the output array */
zend_hash_next_index_insert(Z_ARRVAL_P(subpats), &result_set, sizeof(zval *), NULL);
}
/g な関数でないのでたぶんこちら。
} else { /* single pattern matching */
/* For each subpattern, insert it into the subpatterns array. */
for (i = 0; i < count; i++) {
if (offset_capture) {
add_offset_pair(subpats, (char *)stringlist[i],
offsets[(i<<1)+1] - offsets[i<<1],
offsets[i<<1], subpat_names[i]);
} else {
if (subpat_names[i]) {
add_assoc_stringl(subpats, subpat_names[i], (char *)stringlist[i],
offsets[(i<<1)+1] - offsets[i<<1], 1);
}
add_next_index_stringl(subpats, (char *)stringlist[i],
offsets[(i<<1)+1] - offsets[i<<1], 1);
}
}
}
三つの (char *)stringlist[i] のどれかですね。
最後のかなあ?
というところで時間切れ。
■_
おおまかにいっちゃうとそれは
Ruby の論理演算子
Ruby のブール演算子には見慣れた &&, ||, ! の他に同じ意味で使用できる and, or, not なるものがある。
違いは優先度だけらしい。(and, or, ! のほうが低い)
また、and と or は優先度が同じだが、&& は || より優先度が高いらしい。
慣れているということもあって普段使う分には &&, ||, ! を使うつもりなので問題ないのだが、
以下のコードを試してみた。
f1 = true
f2 = true
f3 = false
f4 = false
r1 = f1 && f2 || f3 && f4
r2 = f1 and f2 or f3 and f4
puts r1
puts r2
実行してみると、どちらも true と表示された。
あれ?
and と or が優先度が同じということは r2 は false にならないとおかしくないか?
((f1 and f2) or f3) and f4 と同等になるのだと思ったんだが
なので、ためしに
r3 = ((f1 && f2) || f3) && f4
r4 = ((f1 and f2) or f3) and f4
puts r3
puts r4
を追加して実行してみると、r3 は false になり r4 は true になった。
何が起こってるのかさっぱりわからんorz
俺はどこをどう考え違いをしているんだろう?
とりあえず and, or は絶対使わないと心に固く決めた。
# 他にもメソッドの引数に渡すときに、and や or を使ってる場合は do_something((flag1 and flag2)) のように括弧を二重にしなければならないとかめんどくさいし。
and と &&、or と || との間の大きな違いはざっくりいうと
expr1 && (||でも状況は一緒)の結果は
式
なのに対して、
expr1 and expr2の結果は
文
というところにあります。ですから、疑問に感じているr2を例にとると
r2 = f1and f2 or f3 and f4
r2 = f1 という文、f2、f3、f4という式文をand/orという演算子で繋いだものという解釈がされるので
r2 に代入されるているのはf1の値だけです。
また、メソッドの引数に使えるのは式であって文ではないので
and/or で繋いだ文を置くとエラーになるというわけです。
余計なカッコで括ることでエラーが解消されるのは、
その余計なカッコにより文が式になったからです。
今更ながら注意: 上記の文章で使った「式」だの「文」だの「式文」だのは
俺様用語であり、Ruby的に正しい(そういう文法定義になっている)かどうかは別の問題ですのであしからず。
■_
Attacking PHP
火種の元w
短いのでちょっと訳してみる。
Mindblind - making web development suck less » Attacking PHP
Attacking PHP
PHPを糾弾する
I am so tired of people defending PHP.
PHPを守ろうとする人たち(=信者とでもする?)にほとほと疲れました。
Note: this is good natured. The guy that wrote the original article - why can I never
find names on these things? - makes a few good points. And, for full disclosure, I
work with PHP full-time right now, and it’s still my go-to language for knocking out
a web application because I’m so familiar with it. (And even then, only with Zend
Framework and phpSprockets.)
#元の指摘をしていたのが良くできていたということ?> this is good natured
# these things って?
“why can I never find names on these things”という
元のアーティクルを書いた彼はいいところをついていたと思います。
But seriously, PHP is sickening. I’ve started using Ruby and Python for any tasks I
can get away with and they’re really worlds apart. PHP’s got some good in it but it’
s all buried under deep layers of hate. That’s right, PHP hates you. PHP is terrible
率直に言って、PHPはむかつくような代物です(sikening)。
わたしはRubyやPythonですべての仕事を片付けるようになって、PHPからはおさらばすることが
できました。PHPはいくつかの良い点もありましたが、
短所は深い階層に隠されていただけだったのです。
PHPはあなたを嫌っています(PHP hates you)。
PHPは恐ろしいもの(酷いもの、のほうが良い?)です。
Need proof? Here it is, broken down by category:
根拠を出せ? よろしい。カテゴリ別に説明しましょう。
Language Features
言語仕様の部
* So many things evaluate to boolean false or boolean true that there had to be a
new operator introduced (=== and !==) to do strict comparisons.
厳密な比較を行うために boolean trueか boolean falseのいずれであるかを
評価する新しい演算子(=== と !==)を導入しました。
* You can’t differentiate between a hash or a list or anything. They’re all the
same. Even if you know you’ll never need a keyed index, you can’t turn it off.
ハッシュとリストなど(たぶん、配列とかそういうデータ構造という意味)を区別することが
できません。なぜならそれらは
実際には同じものだからです。あなたがキーによる添え字付けを決してすることがない
ということがわかっていたとしてもその機能を無効にすることができません。
* It's Object Orientation is broken in places (late static binding).
サポートしているオブジェクト指向はぶっ壊れている代物(late static binding)
* It doesn't support lambas. create_function() is not a lambda.
lambda をサポートしていません。create_function()が返すのは lambdaではありません。
* You never know if short_open_tags is on, or if safe_mode is on, or if (ugh)
register_globals is on.
short_open_tags がオンであるかどうかとか、safe_mode がオンであるかどうか、
あるいは(あのひどい)register_globalがオンかどうかを
知るすべがありません。
2008/2/1 追記:
知ることができないこともないそうです
→ あーありがち - まずダメなところを認めることから始まる
Built-in Functionalty
組み込み関数の部
* It comes with a standard library that has no naming convention. You never know
in what order the words will come in or if they’re separated by underscores or not:
標準ライブラリには命名規則といったものが存在しない。
アンダースコアで分けられたりしている場合もある単語がどのような順番で関数名を
組み立てているのかを理解することができません:
o str_replace() #string + replace アンダースコアあり
o strlen() #string + lenght アンダースコアなし
o parse_str() #parse + string (動詞が先にきている)
* You never know what order the arguments are in:
関数の引数の順番がどんなものかを決して覚えていられないでしょう
o in_array($needle, $haystack)
o strpos($haystack, $needle) #この二つでorder が逆
o You constantly have to check your output thanks to type restrictions:
ありがたくも型を制約するために出力を常にチェックする必要があります:
o strpos('abcd', 'a') will return 0. Don't test this with
strpos('abcd', 'a') は0を返します。次のような検査をしてはいけません
if (strpos('abcd', 'a')) { … }
because 0 is secretly false!
これは関数の戻り値 0 が false だからダメです
You've got to use
このようにしなければなりません
if (strpos('abcd', 'a') !== false).
Common use
A lot of open source projects are written in it, such as Joomla, Wordpress, and
MediaWiki. All of their code is hideous, and half of the time there’s random HTML in
the middle of their scripts because, of course, we’re working with webpages and why
would you ever want to abstract the output from the logic?
たくさんのオープンソースプロジェクトがPHPを使って書かれている。たとえば
Joomla、Wordpress、MediaWikiなど。これらのコードは全てぞっとするような代物で、
スクリプトの中にぐちゃぐちゃなHTML(random HTML)があります。
もちろんそれは、わたしたちがwebページを作るために作業しているためです。
あなたはこれまでにロジックから出力を抽象的なものにしたいとおもったことはありませんか?
Irrelevant praise
見当違いな賞賛
Here are some common praises of PHP and why they don’t matter:
以下にいくつかのPHPに対する褒め言葉と、それが実は意味のないものであるかという理由を挙げる。
PHP is great because it allows the new user to pick it up quickly!
PHPは偉大だ。なぜなら、PHPは新しいユーザーが即座につかうことができるから!
Sure. And if the introductory material available covered good programming style we
might not have a problem. In reality, every example PHP script is riddled with SQL
Injection vulnerabilities, XSS vulnerabilities, and terrible programming. Most newbs
never learn a better way of doing things because this gets them results that look good
very quickly.
確かに。
ただし、わたしたちが問題を抱えないですむかもしれないような良いプログラミングスタイルを
利用できるようにしていてくれていたら。
実際には例に挙げられているPHPスクリプトは、SQLインジェクションや XSS脆弱性、
あるいはそのほかの防御的プログラミングのためにわかりづらいものになっている。
大部分の入門者はそういったことをもっと上手にやる方法を学ぶことは決してない。
なぜならそんなことをしないでも結果を得ることはできるのだから。
PHP has classes, it doesn’t need namespaces.
PHPには名前空間を必要としていないクラスがある。
Fail. Use a language with namespaces for a few months and come back to PHP. I did. It's
sickening.
間違い。名前空間を持っている言語を数ヶ月使って、その後でPHPに戻ってみればいい。
わたしは実際にそれをやった。むかつくこと請け合いだ。
Globals are okay!
いいじゃんGlobals!
Whoever taught you that needs to be shot. Globals are not okay. They are tolerable in
certain situations, but if you make blanket statements like “Globals pierce through
all the layers of code and get right to the heart of the matter.” then you’re
clearly using them too much.
自爆したい人はみんなそう考えるんだよね。Globalはよくない。
我慢できる状況もあるだろうけど、
“Globals pierce through all the layers of code and get right to the heart of the matter.”
のような blanket statementを作ってしまうとそれに頼り切ってしまうんだ。
Defending PHP - Jimbojw.com
Defending PHP
From Jimbojw.com
Jump to: navigation, search
Ugh. I am so tired of defending PHP - even from people I know and respect and who use
it every day. So here I'm going to make my last stand. In all future arguments I get
into, I will point back to this article as my sole defense.
Before you read further, you have to understand that "the curve is a circle", and
those who appear to be beneath you may in fact be your superiors in a given field of
expertise. Never forget this. PHP is awesome
ここから先に読み進めていく前に、"the curve is a circle"を理解しておく必要があります。
また、あなたを抑圧するために現れる人?(who appear to be beneath you)が
given field で
このことを決して忘れないでください。
PHPサイコー。
Need proof? Here it is, broken down by category:
Language Features
* It's dynamically typed.
動的な型付けがされます。
* All arrays are associative (hashes)
すべての配列は連想的なもの(ハッシュ)です。
* It's object oriented with a reflection API.
リフレクションAPIを使ったオブジェクト指向な言語です。
* It uses different operators for numeric addition (+) and string concatenation (.)
数値の加算と文字列の連結とで別々の演算子を使います。
* It supports eval() and lambdas (somewhat)
eval()とlambda(ぽいもの)をサポートしています。
* Can execute system commands and read from local and remote files (all one-liners)
システムコマンドを実行できますし、ローカルなファイルでもリモートのファイルでも
読み込むことが(すべての一行野郎で?)できます。
* Supports coercing scalars into boolean decisions (means you can just do if($x)
instead of if($x!=null && $x!=0 && $x!=false ... )
スカラー値のbooleanへの coercing(変換)をサポートしています
(つまり、if ($x!=null && $x!=0 && $x!=false ...) と書くのではなく
すっきり if ($x)と書くことができます)
* Usable in both web and command-line contexts
Web用にもコマンドライン上でのツールとしても使えます
Built-in Functionality
組み込み関数
* It comes with a vast array of built-in functions to do all sorts of common tasks.
Here are a few off the top of my head:
一般的なタスクすべてをこなすための組み込み関数があります。
ちょっと考え付いただけでも
o Base 64 encoding and decoding
base64エンコーディングとデコーディング
o URL encoding and decoding
URLエンコーディングとデコーディング
o HTML character encoding, decoding and tag stripping
HTMLキャラクタエンコーディングとデコーディング、タグの取り除き
o SAX style XML parsing
SAX形式のXML解析
o REGULAR EXPRESSIONS
正規表現(なぜ大文字で強調?)
o Array sorting, custom sorting
配列のソート。
o md5 and sha1 hashing
md5やsha1を使ったハッシュ
* It can natively connect to the most popular Database engines around.
ほとんどのポピュラーなデータベースエンジンに対してnatively な接続ができます
* It comes prepackaged with graphics manipulation capabilities (GD)
グラフィックを扱うための能力(GD)が備え付けでついています
Community
* It has an active community open to new ideas and ready to help noobs and experts
alike:
新しいアイデアに対して開かれていて、新人やエキスパートをいつでも助けてくれるような
活動的なコミュニティがあります:
o mailing lists
o IRC Channel: irc://irc.freenode.net/php
* Some of the most popular open-source projects in the world are written in it
including:
非常にポピュラーなオープンソースプロジェクトがPHPで書かれています。
o MediaWiki (which powers Wikipedia)
o phpBB
o WordPress
o Joomla! (formerly known as Mambo)
Irrelevant complaints
根拠レスな非難
Now, here are some common complaints about PHP, and why the don't matter:
I don't like PHP because it's not statically typed (like my beloved Java)
静的な型付けをする言語だからPHPは好きじゃない
News flash: static typing sucks - deal.
PHP doesn't have namespaces, so there can be naming collisions.
Oh noes! Seriously, this is a theoretical objection, not a practical problem. Use a
class dude - makes for a nice way to wrap your functions.
I hate globals
Globals can save your life. Globals pierce through all the layers of code and get
right to the heart of the matter. You say you don't like globals, so try to remember
that the next time you grab a singleton from your static factory.
PHP allows/promotes poor programming practices
I call shenanigans on that one. PHP appeals to a broad audience, especially new coders,
because it is ubiquitous. It's just as easy to write poor code in any other language
(an Interface with exactly one Implementation anyone?)
In summary - I'm really tired of having to defend PHP. I feel like I'm the only one
here. Even the developers I know that use it on a daily basis speak ill of it.
Whatever.
There are plenty of reasons we all keep finding ourselves drinking from the PHP
watering hole. If you don't like the taste, you're welcome to leave at any time.
■_
なにいッ
イー・モバイル、EM・ONEのOS有償アップグレードを3月で終了
イー・モバイルは、同社のモバイル端末「EM・ONE」のOS有償アップグレードを3月で終了すると
発表した。
EM・ONEは、Windows Mobile 5をOSに採用したモバイル端末。イー・モバイルでは本体スペッ
クは同等でOSをWindows Mobile 6に変更した「EM・ONE α」を10月5日より発売しており、EM・
ONEについては販売を終了していた。
既存のEM・ONEユーザーに対しては、配送料を含め9,980円でEM・ONEをEM・ONE α相当に有償ア
ップグレードできるサービスを10月5日より実施していたが、3月10日必着分を持ってこのアップ
グレードサービスを終了。窓口での申し込みは3月5日までとなる。
むー、どうしたもんか喃。
■
え゛?
ファイルに書き込む時の負荷について -OKWave
その辺の処理を深く知るためにはCを学ぶと良いです。
phpもCで書かれて居ますから。
質問者様が上げたロジックはおそらく教本に載っていたものだと思いますが。
その二つのコードの違いは「メモリの使いかた」です。
$bufに追記しファイルを出力する方法だと
→$bufに溜め込む
→ファイル出力用にメモリを確保
→$bufをメモリへコピー
→fclose()でファイルへ書き込み
となります。
frite()直書きだと
→ファイル出力用にメモリを確保
→ループ
→出力するデータをメモリに書き込み
←ループ
→fclose()でファイルへ書き込み
となります。
どちらが良いかといえば。
「ケースバイケース」、または「文字列連結の方は駄目」です。
上で書きましたが、ファイルはfclose()が呼ばれた瞬間に物理的な書き込みを行います。
fopen()したあとにflose()をするまでの時間が開けば開くほど書き込むデータの競合が発生しや
すくなります。それを避けるために、fopen()を呼ぶ前にあらかじめ吐き出すデータをメモリに
用意しておき、書くときは一気に書くとしたほうが安全です。ゆえ、よく教本に載っている
fopen()とfclose()の間に文字列連結などのロジックを行うコードは悪質であるといえます。
上のロジックは以下のようにしたほうが良いでしょう。
$buf = "";
for ($i = 1; $i <= 3; $i++) {
$buf .= "aaa$i\n";
}
$fp = fopen("data.txt", "w");
fwrite($fp, $buf);
fclose($fp);
上記のように書くのであれば、あとは環境と相談してどう書くか決めると良いでしょう。
ファイルはfclose()が呼ばれた瞬間に物理的な書き込みを行います
ってどこのなんてOSとライブラリだよ、それw
いくらfwriteしてもバッファに溜め込むだけって?
それと、変数の内容を連結することによるメモリ領域の再確保とかはぜんぜん問題にならないと
思ってらっしゃるわけか、この専門家様は。
いやー参りましたw