1: <?php
2: /*
3: * Copyright (c) 2014 @trashtoy
4: * https://github.com/trashtoy/
5: *
6: * Permission is hereby granted, free of charge, to any person obtaining a copy of
7: * this software and associated documentation files (the "Software"), to deal in
8: * the Software without restriction, including without limitation the rights to use,
9: * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
10: * Software, and to permit persons to whom the Software is furnished to do so,
11: * subject to the following conditions:
12: *
13: * The above copyright notice and this permission notice shall be included in all
14: * copies or substantial portions of the Software.
15: *
16: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
18: * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
19: * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20: * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21: * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22: */
23: /**
24: * PHP class file.
25: * @auhtor trashtoy
26: * @since 2.0.0
27: */
28: namespace Peach\Util;
29:
30: /**
31: * 文字列処理に関するユーティリティクラスです
32: */
33: class Strings
34: {
35: /**
36: * このクラスはインスタンス化することができません.
37: */
38: private function __construct() {}
39:
40: /**
41: * 内部関数の {@link http://jp1.php.net/manual/ja/function.explode.php explode()} のカスタム版です.
42: * 基本的にはオリジナルの explode() と同じですが, 以下の点が異なります.
43: *
44: * - $separator が空文字列の場合に空の配列を返す (オリジナルは FALSE を返す)
45: * - $value が文字列以外の場合, {@link Values::stringValue} の結果を使用する
46: *
47: * 引数をどのように指定しても, 返り値が必ず配列型になることが特徴です.
48: *
49: * @param string $separator セパレータ
50: * @param string $value 対象文字列
51: * @return array セパレータが見つからないときは長さ 1 の配列,
52: * 対象が空文字列の場合は空の配列, それ以外は explode() と同じ.
53: */
54: public static function explode($separator, $value)
55: {
56: if (!is_string($value)) {
57: return self::explode($separator, Values::stringValue($value));
58: }
59: if (strlen($separator)) {
60: return explode($separator, $value);
61: }
62:
63: return array();
64: }
65:
66: /**
67: * 指定された文字列を行単位で分割します.
68: * 引数の文字列を CR, LF, CRLF で分割し, 結果の配列を返します.
69: * 結果の配列の各要素に改行コードは含まれません.
70: *
71: * @param string $str 分割対象の文字列
72: * @return array 行単位で分割された文字列の配列
73: */
74: public static function getLines($str)
75: {
76: return preg_split("/\\r\\n|\\r|\\n/", $str);
77: }
78:
79: /**
80: * 指定された文字列が空白文字の集合からなる文字列かどうかを返します.
81: * @param string $str 検査対象の文字列
82: * @return bool 引数が NULL, 空文字列, "\r", "\n", "\t",
83: * 半角スペースから成る文字列の場合に TRUE, それ以外は FALSE
84: */
85: public static function isWhitespace($str)
86: {
87: return !strlen($str) || !preg_match("/[^\\s]/", $str);
88: }
89:
90: /**
91: * 指定された文字列を基底ディレクトリに変換します.
92: * 引数が空文字列か, '/' で終わる文字列の場合は引数をそのまま返します.
93: * それ以外の場合は, 引数の末尾に '/' を連結した文字列を返します.
94: *
95: * @param string $basedir 変換対象の文字列
96: * @return string 基底ディレクトリ名
97: */
98: public static function basedir($basedir)
99: {
100: if (!is_string($basedir)) {
101: return self::basedir(Values::stringValue($basedir));
102: }
103: if (!strlen($basedir)) {
104: return "";
105: }
106: if (substr($basedir, -1) === "/") {
107: return $basedir;
108: }
109:
110: return $basedir . "/";
111: }
112:
113: /**
114: * 指定された文字列の中で、"\" によるエスケープ処理のされていない文字列があらわれる
115: * 最初のインデックスを返します.
116: * 偶数個の "\" が続いた後に対象の文字列が出現した場合に、そのインデックスを返り値とします.
117: * 奇数個の "\" の後の文字については, その直前の "\" によってエスケープされているとみなして
118: * スルーします. 以下に例を示します.
119: *
120: * <pre>
121: * getRawIndex("AB=CD=EF", "=") => 2
122: * getRawIndex("AB\\=CD=EF", "=") => 6
123: * getRawIndex("AB\\\\=CD=EF", "=") => 4
124: * </pre>
125: *
126: * インデックスが存在しない場合は FALSE を返します.
127: *
128: * @param string $text 検索文字列
129: * @param string $chr 検索対象の文字
130: * @return int インデックス. ただし存在しない場合は FALSE
131: */
132: public static function getRawIndex($text, $chr)
133: {
134: $chr = str_replace("\\", "\\\\", $chr);
135: $pattern = "/(?<!\\\\)(?:\\\\\\\\)*(" . $chr . ".*)$/";
136: $result = array();
137: preg_match($pattern, $text, $result);
138: if (count($result)) {
139: return strlen($text) - strlen($result[1]);
140: } else {
141: return false;
142: }
143: }
144:
145: /**
146: * ある文字列が指定された文字列で始まっているかどうかを判別します.
147: * $prefix が空文字列の場合は TRUE を返します.
148: * 引数が文字列以外の場合は {@link Values::stringValue} が適用されます.
149: *
150: * @param string $text 検査対象の文字列
151: * @param string $prefix 開始する文字列
152: * @return bool 引数 $text の先頭が $prefix である場合に TRUE
153: */
154: public static function startsWith($text, $prefix)
155: {
156: if (!is_string($text)) {
157: return self::startsWith(Values::stringValue($text), $prefix);
158: }
159: if (!is_string($prefix)) {
160: return self::startsWith($text, Values::stringValue($prefix));
161: }
162: if ($prefix === "") {
163: return true;
164: }
165:
166: return (strpos($text, $prefix) === 0);
167: }
168:
169: /**
170: * ある文字列が指定された文字列で終了しているかどうかを判別します.
171: * $suffix が空文字列の場合は TRUE を返します.
172: * 引数が文字列以外の場合は {@link Values::stringValue} が適用されます.
173: *
174: * @param string $text 検査対象の文字列
175: * @param string $suffix 終了する文字列
176: * @return bool 引数 $text の末尾が $suffix に等しい場合に TRUE
177: */
178: public static function endsWith($text, $suffix)
179: {
180: if (!is_string($text)) {
181: return self::endsWith(Values::stringValue($text), $suffix);
182: }
183: if (!is_string($suffix)) {
184: return self::endsWith($text, Values::stringValue($suffix));
185: }
186: if ($suffix === "") {
187: return true;
188: }
189:
190: $index = strlen($text) - strlen($suffix);
191: return substr($text, $index) === $suffix;
192: }
193:
194: /**
195: * ある文字列が指定された文字で終了して, かつエスケープ処理されていないかを判別します.
196: * 以下に例を示します.
197: *
198: * - ("[ABC]", "]") => TRUE
199: * - ("[ABC\\]", "]") => FALSE ("\\" がその後ろの "]" をエスケープしているとみなされる)
200: * - ("[ABC\\\\]", "]") => TRUE ("\\\\" が一つの文字として扱われるため, 直後の "]" に影響しない)
201: *
202: * @param string $text 検査対象の文字列
203: * @param string $chr 検査対象の文字
204: * @return bool 引数 $text の末尾が, '\' でエスケープされていない $chr で終了している場合のみ TRUE
205: */
206: public static function endsWithRawChar($text, $chr)
207: {
208: $chr = str_replace("\\", "\\\\", $chr);
209: $pattern = "/(?<!\\\\)(?:\\\\\\\\)*(" . $chr . ")$/";
210: $result = preg_match($pattern, $text);
211: return (0 < $result);
212: }
213:
214: /**
215: * 文字列内に含まれる {0}, {1}, {2} などのテンプレート変数を, $args 内の各要素で置き換えます. 例えば
216: * <code>
217: * template('My name is {0}. I am {1} years old', array('Taro', 18));
218: * </code>
219: * の結果は次のようになります.
220: * <code>
221: * "My name is Taro. I am 18 years old"
222: * </code>
223: *
224: * $template が NULL の場合は NULL を返します.
225: *
226: * @param string $template テンプレート
227: * @param array $args 置き換える内容の配列
228: * @return string テンプレートの適用結果
229: */
230: public static function template($template, array $args = array())
231: {
232: if ($template === null) {
233: return null;
234: }
235:
236: $subject = Values::stringValue($template);
237: $replaces = array();
238: foreach ($args as $key => $value) {
239: $from = "{" . $key . "}";
240: $replaces[$from] = $value;
241: }
242: return strtr($subject, $replaces);
243: }
244: }
245: