こちらもよく忘れてしまうので備忘メモです
substr、strlen、strposを組み合わせて、文字列中に特定文字から特定文字の間を切り出すような操作をやります
順序だてて説明していきます
——注意事項——
記事書いてる途中で、わたしの師匠的な人に聞いたのですが、「phpでsubstr、strlen、strposを使って切り出すようなやり方はアホやで、そんなやり方C言語くらいやろ」という指摘を頂戴しました・・・せっかくなんで、文字列操作的な参考になれば、と記事は書きますが、今回のやり方で切り出しはやめた方がよいです・・・。
preg_matchを使って簡単にできるので、コッチの記事を参考にしてみてください~_:(´ཀ`」 ∠):
substr
まずは文字列中から切り出すsubstrです
string substr(string 対象の文字列, int 開始位置, int 切り出す文字列の長さ)
引数 | 説明 |
---|---|
対象の文字列 | 切り出す対象の文字列です |
開始位置 | どこから切り出しを開始するか 先頭は0です 負の場合は文字列を後ろから数えます |
切り出す文字列の長さ | 開始位置から切り出す文字列の文字数 負の場合は後ろから数えた位置まで切り出します |
PHPのマニュアルを見ればだいたい分かりますので、サンプルは雑ですがマニュアルをそのまま貼っておきます
1 2 3 4 5 | echo substr ( 'abcdef' , 1); // bcdef echo substr ( 'abcdef' , 1, 3); // bcd echo substr ( 'abcdef' , 0, 4); // abcd echo substr ( 'abcdef' , 0, 8); // abcdef echo substr ( 'abcdef' , -1, 1); // f |
ちなみにマルチバイト文字(主に日本語)の場合はmb_substrを使います
mb_substr
string mb_substr(string 対象の文字列, int 開始位置, int 切り出す文字列の長さ, string エンコーディング)
引数 | 説明 |
---|---|
切り出す文字列の長さ | 基本同じですが、NULLの場合は文字列の最後まで |
エンコーディング | エンコードを指定します、省略すると内部文字エンコーディングが使われるので文字化けの原因になると思います |
例えば以下は文字化けしてしまうので、mb_substrを使って切り出します
1 2 | echo substr ( 'あいうえお' , 1); // 文字化けしちゃう echo mb_substr( 'あいうえお' , 1, NULL, "UTF-8" ); // いうえお |
strpos
続いて、文字列中から特定の文字の位置を探すstrposです
コイツを使って、文字列中のどこからどこまでを切り出すか特定します
int strpos(string 対象の文字列, mixed 検索文字列, int 検索開始位置)
引数 | 説明 |
---|---|
検索文字列 | 対象の文字列から探す文字列です |
検索開始位置 | 指定すると、対象の文字列の検索を開始する位置を指定できます |
1 2 3 4 5 6 7 | echo strpos ( 'abcdef' , 'c' ); // 2 echo strpos ( 'abcdef' , 'c' , 3); // FALSE // 3(dの位置)から探すとcは見つからない echo strpos ( 'abcdcf' , 'c' , 3). "<br>" ; // 4 // 2の位置にもcがあるが、3の位置から探しているので |
ちなみにこちらもsubstrと同様にマルチバイト文字に対応したmb_strposがあります、詳細は省略します
strlen
最後に文字列の長さを返すstrlenです
特定の文字を検索して開始位置を定める際に、文字自体の長さを調べる必要があります
int strlen(string 対象の文字列)
ただただ文字の長さを返すだけですね
1 2 3 4 5 | $str = 'abcdef' ; echo strlen ( $str ); // 6 $str = ' ab cd ' ; echo strlen ( $str ); // 7 |
文字列中から特定の部分を切り出す
それでは本題です、以下サンプルソースです
今回は$target_textの文中から「ココ」を抜き出したいと思います
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | //対象の文字列 $target_text = "この文章からdelimココ区切りを抽出します" ; //区切り文字(開始) $delimiter_start = "delim" ; //区切り文字(終了) $delimiter_end = "区切り" ; //開始位置 $start_position = strpos ( $target_text , $delimiter_start ) + strlen ( $delimiter_start ); //切り出す部分の長さ $length = strpos ( $target_text , $delimiter_end ) - $start_position ; //切り出し print substr ( $target_text , $start_position , $length ); |
少し補足
開始位置は検索対象の文字列から探しますが、strposは見つかった最初の位置を返すので、文字自体の長さ(今回は「delim」の5文字分)が考慮されていません。なので、strlenの分だけ開始位置を後ろにずらします。
終了位置も補正が必要で、切り出したい文字列の長さを求めます。今回の場合は、
「この文章からdelimココ」の長さから「この文章からdelim」の長さを引いた、つまりは「ココ」の長さ2文字分を求める必要がありますね。
通りがかって見つけ、すごく使用方法が分かりやすい記事で良いと思いました。
しかしながら注意事項に書かれていることに関していくつか補足させてください。
>「phpでsubstr、strlen、strposを使って切り出すようなやり方はアホやで、そんなやり方C言語くらいやろ」という指摘を頂戴しました・・・せっかくなんで、文字列操作的な参考になれば、と記事は書きますが、今回のやり方で切り出しはやめた方がよいです・・・。
こちらに関してですが、可能な限りはstr系関数を利用した方が良いです。
理由は実装工数だけでなくコードの可読性、またパフォーマンス面においても優れているためです。むしろ、これらのstr系関数で賄えない場合に正規表現(preg)系関数の利用を検討してほしいです。
特に正規表現が複雑になると、読みにくいコードとなり、利用方法によってはパフォーマンスの悪化を招きます。下記の例が参考になるでしょう。↓
https://postd.cc/regexes-the-bad-the-better-and-the-best/
なおphp公式ドキュメント上にも、利用用途に応じた正規表現との使い分けが推奨されています。
https://www.php.net/manual/ja/function.preg-match.php
↑preg_matchの注意の部分
https://www.php.net/manual/ja/function.strstr.php
↑こちらはstrstrの場合ですが、同じく注意の部分
パフォーマンスの詳細に関しては検証されている方の記事がいくらかあるので、読んでみると参考になるでしょう。
お役に立てれば幸いです。