mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
[RFC] Add mb_ucfirst and mb_lcfirst functions (#13161)
This commit is contained in:
1
NEWS
1
NEWS
@@ -90,6 +90,7 @@ PHP NEWS
|
||||
|
||||
- MBString:
|
||||
. Added mb_trim, mb_ltrim and mb_rtrim. (Yuya Hamada)
|
||||
. Added mb_ucfirst and mb_lcfirst. (Yuya Hamada)
|
||||
|
||||
- MySQLnd:
|
||||
. Fixed bug GH-13440 (PDO quote bottleneck). (nielsdos)
|
||||
|
||||
@@ -431,6 +431,8 @@ PHP 8.4 UPGRADE NOTES
|
||||
- MBString:
|
||||
. Added mb_trim, mb_ltrim and mb_rtrim functions.
|
||||
RFC: https://wiki.php.net/rfc/mb_trim
|
||||
. Added mb_ucfirst and mb_lcfirst functions.
|
||||
RFC: https://wiki.php.net/rfc/mb_ucfirst
|
||||
|
||||
- Opcache:
|
||||
. If JIT is enabled, PHP will now exit with a fatal error on startup in case
|
||||
|
||||
@@ -2951,6 +2951,50 @@ PHP_FUNCTION(mb_strtolower)
|
||||
RETURN_STR(mbstring_convert_case(PHP_UNICODE_CASE_LOWER, ZSTR_VAL(str), ZSTR_LEN(str), enc));
|
||||
}
|
||||
|
||||
static void php_mb_ulcfirst(INTERNAL_FUNCTION_PARAMETERS, php_case_mode mode)
|
||||
{
|
||||
zend_string *str, *from_encoding = NULL;
|
||||
|
||||
ZEND_PARSE_PARAMETERS_START(1, 2)
|
||||
Z_PARAM_STR(str)
|
||||
Z_PARAM_OPTIONAL
|
||||
Z_PARAM_STR_OR_NULL(from_encoding)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
|
||||
const mbfl_encoding *enc = php_mb_get_encoding(from_encoding, 2);
|
||||
if (!enc) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
zend_string *first = mb_get_substr(str, 0, 1, enc);
|
||||
zend_string *head = mbstring_convert_case(mode, ZSTR_VAL(first), ZSTR_LEN(first), enc);
|
||||
|
||||
if (zend_string_equals(first, head)) {
|
||||
zend_string_release_ex(first, false);
|
||||
zend_string_release_ex(head, false);
|
||||
RETURN_STR(zend_string_copy(str));
|
||||
}
|
||||
|
||||
zend_string *second = mb_get_substr(str, 1, MBFL_SUBSTR_UNTIL_END, enc);
|
||||
zend_string *retval = zend_string_concat2(ZSTR_VAL(head), ZSTR_LEN(head), ZSTR_VAL(second), ZSTR_LEN(second));
|
||||
|
||||
zend_string_release_ex(first, false);
|
||||
zend_string_release_ex(head, false);
|
||||
zend_string_release_ex(second, false);
|
||||
|
||||
RETVAL_STR(retval);
|
||||
}
|
||||
|
||||
PHP_FUNCTION(mb_ucfirst)
|
||||
{
|
||||
php_mb_ulcfirst(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_UNICODE_CASE_TITLE);
|
||||
}
|
||||
|
||||
PHP_FUNCTION(mb_lcfirst)
|
||||
{
|
||||
php_mb_ulcfirst(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_UNICODE_CASE_LOWER);
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
MB_LTRIM = 1,
|
||||
MB_RTRIM = 2,
|
||||
|
||||
@@ -135,6 +135,10 @@ function mb_strtoupper(string $string, ?string $encoding = null): string {}
|
||||
/** @refcount 1 */
|
||||
function mb_strtolower(string $string, ?string $encoding = null): string {}
|
||||
|
||||
function mb_ucfirst(string $string, ?string $encoding = null): string {}
|
||||
|
||||
function mb_lcfirst(string $string, ?string $encoding = null): string {}
|
||||
|
||||
function mb_trim(string $string, string $characters = " \f\n\r\t\v\x00\u{00A0}\u{1680}\u{2000}\u{2001}\u{2002}\u{2003}\u{2004}\u{2005}\u{2006}\u{2007}\u{2008}\u{2009}\u{200A}\u{2028}\u{2029}\u{202F}\u{205F}\u{3000}\u{0085}\u{180E}", ?string $encoding = null): string {}
|
||||
|
||||
function mb_ltrim(string $string, string $characters = " \f\n\r\t\v\x00\u{00A0}\u{1680}\u{2000}\u{2001}\u{2002}\u{2003}\u{2004}\u{2005}\u{2006}\u{2007}\u{2008}\u{2009}\u{200A}\u{2028}\u{2029}\u{202F}\u{205F}\u{3000}\u{0085}\u{180E}", ?string $encoding = null): string {}
|
||||
|
||||
10
ext/mbstring/mbstring_arginfo.h
generated
10
ext/mbstring/mbstring_arginfo.h
generated
@@ -1,5 +1,5 @@
|
||||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: 0fe7418224f3a0ab65a06bf215ebcb09ce632488 */
|
||||
* Stub hash: ea642b9010bc38a3b13710662fef48663d4385e1 */
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_mb_language, 0, 0, MAY_BE_STRING|MAY_BE_BOOL)
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, language, IS_STRING, 1, "null")
|
||||
@@ -118,6 +118,10 @@ ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_mb_strtolower arginfo_mb_strtoupper
|
||||
|
||||
#define arginfo_mb_ucfirst arginfo_mb_strtoupper
|
||||
|
||||
#define arginfo_mb_lcfirst arginfo_mb_strtoupper
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mb_trim, 0, 1, IS_STRING, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, string, IS_STRING, 0)
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, characters, IS_STRING, 0, "\" \\f\\n\\r\\t\\v\\x00
\"")
|
||||
@@ -348,6 +352,8 @@ ZEND_FUNCTION(mb_convert_encoding);
|
||||
ZEND_FUNCTION(mb_convert_case);
|
||||
ZEND_FUNCTION(mb_strtoupper);
|
||||
ZEND_FUNCTION(mb_strtolower);
|
||||
ZEND_FUNCTION(mb_ucfirst);
|
||||
ZEND_FUNCTION(mb_lcfirst);
|
||||
ZEND_FUNCTION(mb_trim);
|
||||
ZEND_FUNCTION(mb_ltrim);
|
||||
ZEND_FUNCTION(mb_rtrim);
|
||||
@@ -445,6 +451,8 @@ static const zend_function_entry ext_functions[] = {
|
||||
ZEND_FE(mb_convert_case, arginfo_mb_convert_case)
|
||||
ZEND_FE(mb_strtoupper, arginfo_mb_strtoupper)
|
||||
ZEND_FE(mb_strtolower, arginfo_mb_strtolower)
|
||||
ZEND_FE(mb_ucfirst, arginfo_mb_ucfirst)
|
||||
ZEND_FE(mb_lcfirst, arginfo_mb_lcfirst)
|
||||
ZEND_FE(mb_trim, arginfo_mb_trim)
|
||||
ZEND_FE(mb_ltrim, arginfo_mb_ltrim)
|
||||
ZEND_FE(mb_rtrim, arginfo_mb_rtrim)
|
||||
|
||||
108
ext/mbstring/tests/mb_ucfirst_lcfirst.phpt
Normal file
108
ext/mbstring/tests/mb_ucfirst_lcfirst.phpt
Normal file
@@ -0,0 +1,108 @@
|
||||
--TEST--
|
||||
mb_ucfirst(), mb_lcfirst functions tests
|
||||
--EXTENSIONS--
|
||||
mbstring
|
||||
--FILE--
|
||||
<?php
|
||||
mb_internal_encoding("UTF-8");
|
||||
|
||||
function test_ascii_mb_ucfirst() {
|
||||
for ($i = 0; $i < 128; $i++) {
|
||||
if ($i >= 97 && $i <= 122) { /* a to z */
|
||||
if (mb_ucfirst(chr($i)) !== chr($i - (97 - 65))) {
|
||||
echo "mb_ucfirst compare failed: " . chr($i) . "\n";
|
||||
}
|
||||
} else {
|
||||
if (mb_ucfirst(chr($i)) !== chr($i)) {
|
||||
echo "mb_ucfirst compare failed: " . chr($i) . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
echo "Done mb_ucfirst\n";
|
||||
}
|
||||
|
||||
function test_ascii_mb_lcfirst() {
|
||||
for ($i = 0; $i < 128; $i++) {
|
||||
if ($i >= 65 && $i <= 90) { /* A to Z */
|
||||
if (mb_lcfirst(chr($i)) !== chr($i + (97 - 65))) {
|
||||
echo "mb_lcfirst compare failed: " . chr($i) . "\n";
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (mb_lcfirst(chr($i)) !== chr($i)) {
|
||||
echo "mb_lcfirst compare failed: " . chr($i) . "\n";
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
echo "Done mb_lcfirst\n";
|
||||
}
|
||||
|
||||
echo "== Empty String ==\n";
|
||||
var_dump(mb_ucfirst(""));
|
||||
var_dump(mb_lcfirst(""));
|
||||
echo "== ASCII ==\n";
|
||||
test_ascii_mb_ucfirst();
|
||||
test_ascii_mb_lcfirst();
|
||||
echo "== mb_ucfirst ==\n";
|
||||
var_dump(mb_ucfirst("ab"));
|
||||
var_dump(mb_ucfirst("ABS"));
|
||||
var_dump(mb_ucfirst("đắt quá!"));
|
||||
var_dump(mb_ucfirst("აბგ"));
|
||||
var_dump(mb_ucfirst("lj"));
|
||||
echo "== mb_lcfirst ==\n";
|
||||
var_dump(mb_lcfirst("ABS"));
|
||||
var_dump(mb_lcfirst("Xin chào"));
|
||||
var_dump(mb_lcfirst("Đẹp quá!"));
|
||||
echo "== SJIS ==\n";
|
||||
var_dump(bin2hex(mb_ucfirst(mb_convert_encoding("ebi", "SJIS", "UTF-8"), "SJIS")));
|
||||
var_dump(bin2hex(mb_lcfirst(mb_convert_encoding("EBI", "SJIS", "UTF-8"), "SJIS")));
|
||||
var_dump(bin2hex(mb_ucfirst(hex2bin("8471"), "SJIS"))); /* б */
|
||||
var_dump(bin2hex(mb_lcfirst(hex2bin("8441"), "SJIS"))); /* Б */
|
||||
var_dump(bin2hex(mb_ucfirst(hex2bin("83bf"), "SJIS"))); /* α */
|
||||
var_dump(bin2hex(mb_lcfirst(hex2bin("839f"), "SJIS"))); /* Α */
|
||||
var_dump(bin2hex(mb_lcfirst(hex2bin("82a0"), "SJIS"))); /* あ */
|
||||
var_dump(bin2hex(mb_ucfirst(hex2bin("83bf8471"), "SJIS")));
|
||||
var_dump(bin2hex(mb_lcfirst(hex2bin("839f8441"), "SJIS")));
|
||||
echo "== EUC-JP ==\n";
|
||||
var_dump(bin2hex(mb_ucfirst(hex2bin("a6d8"), "EUC-JP"))); /* Ω */
|
||||
var_dump(bin2hex(mb_lcfirst(hex2bin("a6b8"), "EUC-JP"))); /* ω */
|
||||
var_dump(bin2hex(mb_ucfirst(hex2bin("a4a2a4a2"), "EUC-JP"))); /* あ */
|
||||
echo "== Longer strings ==\n";
|
||||
var_dump(mb_ucfirst("э" . str_repeat("A", 65536)) === "Э" . str_repeat("A", 65536));
|
||||
var_dump(mb_lcfirst("Э" . str_repeat("A", 65536)) === "э" . str_repeat("A", 65536));
|
||||
?>
|
||||
--EXPECT--
|
||||
== Empty String ==
|
||||
string(0) ""
|
||||
string(0) ""
|
||||
== ASCII ==
|
||||
Done mb_ucfirst
|
||||
Done mb_lcfirst
|
||||
== mb_ucfirst ==
|
||||
string(6) "Ab"
|
||||
string(9) "ABS"
|
||||
string(12) "Đắt quá!"
|
||||
string(9) "აბგ"
|
||||
string(2) "Lj"
|
||||
== mb_lcfirst ==
|
||||
string(9) "aBS"
|
||||
string(9) "xin chào"
|
||||
string(12) "đẹp quá!"
|
||||
== SJIS ==
|
||||
string(12) "826482828289"
|
||||
string(12) "828582618268"
|
||||
string(4) "8441"
|
||||
string(4) "8471"
|
||||
string(4) "839f"
|
||||
string(4) "83bf"
|
||||
string(4) "82a0"
|
||||
string(8) "839f8471"
|
||||
string(8) "83bf8441"
|
||||
== EUC-JP ==
|
||||
string(4) "a6b8"
|
||||
string(4) "a6d8"
|
||||
string(8) "a4a2a4a2"
|
||||
== Longer strings ==
|
||||
bool(true)
|
||||
bool(true)
|
||||
Reference in New Issue
Block a user