Дата обновления перевода 2022-01-03

Компонент Строка

Компонент Строка предоставляет API, ориентированный на один объект, для работы с треями “модульными системами” строк: байтами, кодовыми точками и графемами.

New in version 5.0: Компонент Строка был представлен в Symfony 5.0.

Установка

1
$ composer require symfony/string

Note

If you install this component outside of a Symfony application, you must require the vendor/autoload.php file in your code to enable the class autoloading mechanism provided by Composer. Read this article for more details.

Что такое Строка?

Вы можете пропустить этот раздел, если вы уже знаете, что такое “кодовая точка” или “графема” в контексте обработки строк. Если нет, то прочтите этот раздел, чтобы изучить терминологию, используемую данным компонентом.

Языки, вроде английского, требуют очень ограниченного набора знаков и символов для отображения любого содержания. Каждая строка - это набор знаков (букв или символов), которые могут быть зашифрованы даже с наиболее ограниченными стандартами (например, ASCII).

Однако, другие языки требуют тысячи знаков для отображения своего содержания. Им необходимы сложные стандарты шифрования вроде Юникод и концепции типа “знак” больше не имеют смысла. Вместо этого, вам нужно будет сталкиваться с такими терминами:

  • Кодовые точки: это элементарная единица информации. Строка - это серия кодовых точек. Каждая кодовая точка - это число, значение которого предоставляется стандартом Юникод. Например, английская буква A - это кодовая точка U+0041, а японская кана - это кодовая точка U+306E.
  • Графемы: это последовательность одной или более кодовых точек, которые отображаются в виде единой графической единицы. Например, испанская буква ñ - это графема, содержащая две кодовые точки: U+006E = n (“маленькая буква N латиницей”) + U+0303 = ◌̃ (“комбинирующая тильда”).
  • Байты: реальная информация, хранящаясь в содержании строки. Каждая кодовая точка может требовать один или более байтов хранения в зависимости от используемого стандарта (UTF-8, UTF-16, и т.д.).

Следующее изображение отображает байты, кодовые точки и графемы для одного и того же слова, написанного на английском (hello), и хинди (नमस्ते):

../_images/bytes-points-graphemes.png

Использование

Создайте новый объект типа ByteString, CodePointString или UnicodeString, передайте содержание строки как его аргументы, а затем используйте объектно-ориентированный API для работы с этими строками:

use Symfony\Component\String\UnicodeString;

$text = (new UnicodeString('This is a déjà-vu situation.'))
    ->trimEnd('.')
    ->replace('déjà-vu', 'jamais-vu')
    ->append('!');
// $text = 'This is a jamais-vu situation!'

$content = new UnicodeString('नमस्ते दुनिया');
if ($content->ignoreCase()->startsWith('नमस्ते')) {
    // ...
}

Справочник методов

Методы создания объектов строки

Для начала, вы можете создавать объекты, готовые для хранения строк как байтов, кодовых точек и графем со следующими классами:

use Symfony\Component\String\ByteString;
use Symfony\Component\String\CodePointString;
use Symfony\Component\String\UnicodeString;

$foo = new ByteString('hello');
$bar = new CodePointString('hello');
// UnicodeString is the most commonly used class
$baz = new UnicodeString('hello');

Используйте статический метод wrap(), чтобы инстанциировать более одного объекта строки:

$contents = ByteString::wrap(['hello', 'world']);        // $contents = ByteString[]
$contents = UnicodeString::wrap(['I', '❤️', 'Symfony']); // $contents = UnicodeString[]

// используйте метод распаковки, чтобы создать инверсированную конверсию
$contents = UnicodeString::unwrap([
    new UnicodeString('hello'), new UnicodeString('world'),
]); // $contents = ['hello', 'world']

Если вы работаете со множеством объектов Строки, рассмотрите использование сокращений функций, чтобы сделать ваш код более емким:

// функция b() создает байтовые строки
use function Symfony\Component\String\b;

// обе строчки одинаковы
$foo = new ByteString('hello');
$foo = b('hello');

// функция u() создает строки Юникода
use function Symfony\Component\String\u;

// обе строчки одинаковы
$foo = new UnicodeString('hello');
$foo = u('hello');

// функция s() создайте байтовую строку или строку Юникода
// depending on the given contents
use function Symfony\Component\String\s;

// создает объект ByteString
$foo = s("\xfe\xff");
// создает объект UnicodeString
$foo = s('अनुच्छेद');

New in version 5.1: Функция s() была представлена в Symfony 5.1.

Также существуют специальные конструкторы:

// ByteString может создать произвольную строку заданной длины
$foo = ByteString::fromRandom(12);
// по умолчанию, произвольные строки используют символы A-Za-z0-9; вы можете ограничить
// используемые символы с помощью второго необязательного аргумента
$foo = ByteString::fromRandom(6, 'AEIOU0123456789');
$foo = ByteString::fromRandom(10, 'qwertyuiop');

// CodePointString и UnicodeString могут создать строку из кодовых точек
$foo = UnicodeString::fromCodePoints(0x928, 0x92E, 0x938, 0x94D, 0x924, 0x947);
// эквивалентно: $foo = new UnicodeString('नमस्ते');

New in version 5.1: Второй аргумент ByteString::fromRandom() был представлен в Symfony 5.1.

Методы преобразования объектов строки

Каждый объект строки может быть преобразован в два других типа объекта:

$foo = ByteString::fromRandom(12)->toCodePointString();
$foo = (new CodePointString('hello'))->toUnicodeString();
$foo = UnicodeString::fromCodePoints(0x68, 0x65, 0x6C, 0x6C, 0x6F)->toByteString();

// необязательный аргумент $toEncoding определяет шифрование целевой строки
$foo = (new CodePointString('hello'))->toByteString('Windows-1252');
// необязательный аргумент $fromEncoding определяет шифрование изначальной строки
$foo = (new ByteString('さよなら'))->toCodePointString('ISO-2022-JP');

Если преобразование невозможно по какой-либо причине, вы получите InvalidArgumentException.

Также существует метод получения байтов, хранящихся в каком-то месте:

// ('नमस्ते' bytes = [224, 164, 168, 224, 164, 174, 224, 164, 184,
//                  224, 165, 141, 224, 164, 164, 224, 165, 135])
b('नमस्ते')->bytesAt(0);   // [224]
u('नमस्ते')->bytesAt(0);   // [224, 164, 168]

b('नमस्ते')->bytesAt(1);   // [164]
u('नमस्ते')->bytesAt(1);   // [224, 164, 174]

Методы, связанные с длиной и свободными пространствами

// возвращает количество графем, кодовых точек или байтов заданной строки
$word = 'नमस्ते';
(new ByteString($word))->length();      // 18 (байтов)
(new CodePointString($word))->length(); // 6 (кодовых точек)
(new UnicodeString($word))->length();   // 4 (графем)

// некоторые символы требуют вдвое больше пространства, чем другие, для отображения при использовании
// моноширинного шрифта (например, в консоли). Этот метод возвращает общую длину, необходимую для
// отображения всего слова
$word = 'नमस्ते';
(new ByteString($word))->width();      // 18
(new CodePointString($word))->width(); // 4
(new UnicodeString($word))->width();   // 4
// если текст содержит несколько строчек, он возвращает максимальную длину всех строчек
$text = "<<<END
This is a
multiline text
END";
u($text)->width(); // 14

// возвращает TRUE только если строка является пустой (даже без сводоных пространств)
u('hello world')->isEmpty();  // false
u('     ')->isEmpty();        // false
u('')->isEmpty();             // true

// удаляет все свободные пространства с начала до конца строки и заменяет два или
// более последовательных пробела внутри содержания на один
u("  \n\n   hello        world \n    \n")->collapseWhitespace(); // 'hello world'

Методы изменения регистра

// изменяет все графемы/кодовые точки на нижний регистр
u('FOO Bar')->lower();  // 'foo bar'

// при работе с разными языками, нижнего/верхнего регистра недостаточно
// тогда регистра три (нижний, верхний, заглавный), некоторые символы не имеют регистра,
// регистр чувствителен к контексту, локали и т.д.
// этот метод возвращает строку, которую вы можете использовать в нечувствительных к регистру сравнениях
u('FOO Bar')->folded();             // 'foo bar'
u('Die O\'Brian Straße')->folded(); // "die o'brian strasse"

// изменяет все графемы/кодовые точки на верхний регистр
u('foo BAR')->upper(); // 'FOO BAR'

// изменяет все графемы/кодовые точки на "заглавный регистр"
u('foo bar')->title();     // 'Foo bar'
u('foo bar')->title(true); // 'Foo Bar'

// изменяет все графемы/кодовые точки на camelCase
u('Foo: Bar-baz.')->camel(); // 'fooBarBaz'
// изменяет все графемы/кодовые точки на snake_case
u('Foo: Bar-baz.')->snake(); // 'foo_bar_baz'
// других регистров можно достичь, изменив методы. Например, PascalCase:
u('Foo: Bar-baz.')->camel()->title(); // 'FooBarBaz'

Методы всех классов строк чувствительны к регистру по умолчанию. Вы можете выполнить нечувствительные к регистру операции с помощью метода ignoreCase():

u('abc')->indexOf('B');               // null
u('abc')->ignoreCase()->indexOf('B'); // 1

Методы добавления к началу и концу

// добавляет заданное содержание (одну или более строк) в начале/конце строки
u('world')->prepend('hello');      // 'helloworld'
u('world')->prepend('hello', ' '); // 'hello world'

u('hello')->append('world');      // 'helloworld'
u('hello')->append(' ', 'world'); // 'hello world'

// добавляет заданное содержание в начале строки (или удаляет его), чтобы гарантировать, что
// содержание начнается именно с этого
u('Name')->ensureStart('get');       // 'getName'
u('getName')->ensureStart('get');    // 'getName'
u('getgetName')->ensureStart('get'); // 'getName'
// этот метод похож, но работает с концом содержания, а не с началом
u('User')->ensureEnd('Controller');           // 'UserController'
u('UserController')->ensureEnd('Controller'); // 'UserController'
u('UserControllerController')->ensureEnd('Controller'); // 'UserController'

// возвращает все содержание, найденное до/после первого появления заданной строки
u('hello world')->before('world');   // 'hello '
u('hello world')->before('o');       // 'hell'
u('hello world')->before('o', true); // 'hello'

u('hello world')->after('hello');   // ' world'
u('hello world')->after('o');       // ' world'
u('hello world')->after('o', true); // 'o world'

// возвращает все содержание, найденное до/после последнего появления заданной строки
u('hello world')->beforeLast('o');       // 'hello w'
u('hello world')->beforeLast('o', true); // 'hello wo'

u('hello world')->afterLast('o');       // 'rld'
u('hello world')->afterLast('o', true); // 'orld'

Методы заполнения и усечения

// делает строку той же длины, что и первый аргумент, добавляя заданную
// строку в начале, конце или по обе стороны строки
u(' Lorem Ipsum ')->padBoth(20, '-'); // '--- Lorem Ipsum ----'
u(' Lorem Ipsum')->padStart(20, '-'); // '-------- Lorem Ipsum'
u('Lorem Ipsum ')->padEnd(20, '-');   // 'Lorem Ipsum --------'

// повторяет заданную строку то количество раз, которое передано в аргументе
u('_.')->repeat(10); // '_._._._._._._._._._.'

// удаляет заданные символы (по умолчанию, свободные пространства) из строки
u('   Lorem Ipsum   ')->trim(); // 'Lorem Ipsum'
u('Lorem Ipsum   ')->trim('m'); // 'Lorem Ipsum   '
u('Lorem Ipsum')->trim('m');    // 'Lorem Ipsu'

u('   Lorem Ipsum   ')->trimStart(); // 'Lorem Ipsum   '
u('   Lorem Ipsum   ')->trimEnd();   // '   Lorem Ipsum'

// удаляет заданное содержание с начала/конца строки
u('file-image-0001.png')->trimPrefix('file-');           // 'image-0001.png'
u('file-image-0001.png')->trimPrefix('image-');          // 'file-image-0001.png'
u('file-image-0001.png')->trimPrefix('file-image-');     // '0001.png'
u('template.html.twig')->trimSuffix('.html');            // 'template.html.twig'
u('template.html.twig')->trimSuffix('.twig');            // 'template.html'
u('template.html.twig')->trimSuffix('.html.twig');       // 'template'
// при передаче массива префисков/суфиксов, усекается только первый найденный
u('file-image-0001.png')->trimPrefix(['file-', 'image-']); // 'image-0001.png'
u('template.html.twig')->trimSuffix(['.twig', '.html']);   // 'template.html'

New in version 5.4: Методы trimPrefix() м trimSuffix() были представлены в Symfony 5.4.

Методы поиска и замены

// проверяет, начинается/заканчивается ли строка с заданной строки
u('https://symfony.com')->startsWith('https'); // true
u('report-1234.pdf')->endsWith('.pdf');        // true

// проверяет, точно ли содержание строки соответствует заданному содержанию
u('foo')->equalsTo('foo'); // true

// проверяет, соответствует ли содержание строки заданному регулярному выражению
u('avatar-73647.png')->match('/avatar-(\d+)\.png/');
// result = ['avatar-73647.png', '73647']

// проверяет, содержит ли строка любую из заданных строк
u('aeiou')->containsAny('a');                 // true
u('aeiou')->containsAny(['ab', 'efg']);       // false
u('aeiou')->containsAny(['eio', 'foo', 'z']); // true

// находит местоположение первого обнаружения заданной строки
// (второй аргумент - местоположение, откуда начинается поиск, негативные
// значения имеют то же значение, что и в PHP-функциях)
u('abcdeabcde')->indexOf('c');     // 2
u('abcdeabcde')->indexOf('c', 2);  // 2
u('abcdeabcde')->indexOf('c', -4); // 7
u('abcdeabcde')->indexOf('eab');   // 4
u('abcdeabcde')->indexOf('k');     // null

// находит местоположение последнего обнаружения заданной строки
// (второй аргумент - местоположение, откуда начинается поиск, негативные
// значения имеют то же значение, что и в PHP-функциях)
u('abcdeabcde')->indexOfLast('c');     // 7
u('abcdeabcde')->indexOfLast('c', 2);  // 7
u('abcdeabcde')->indexOfLast('c', -4); // 2
u('abcdeabcde')->indexOfLast('eab');   // 4
u('abcdeabcde')->indexOfLast('k');     // null

// заменяет все обнаружения заданной строки
u('http://symfony.com')->replace('http://', 'https://'); // 'https://symfony.com'
// заменяет все обнаружения заданного регулярного выражения
u('(+1) 206-555-0100')->replaceMatches('/[^A-Za-z0-9]++/', ''); // '12065550100'
// вы можете передать вызываемое в качестве второго аргумента, чтобы выполнить продвинутые замены
u('123')->replaceMatches('/\d/', function ($match) {
    return '['.$match[0].']';
}); // result = '[1][2][3]'

New in version 5.1: Метод containsAny() был представлен в Symfony 5.1.

Методы объединения, разделения, усечения и реверса

// использует строку в качестве "клея" для объединения всех заданных строк
u(', ')->join(['foo', 'bar']); // 'foo, bar'

// разбивает строку на части, используя заданный разделитель
u('template_name.html.twig')->split('.');    // ['template_name', 'html', 'twig']
// вы можете установить макисмальное количество частей в качестве второго аргумента
u('template_name.html.twig')->split('.', 2); // ['template_name', 'html.twig']

// возвращает подстроку, которая начинается с первого аргумента и имеет длину второго
// необязательного аргумента (негативные значения имеют то же значение, что и в PHP-функциях)
u('Symfony is great')->slice(0, 7);  // 'Symfony'
u('Symfony is great')->slice(0, -6); // 'Symfony is'
u('Symfony is great')->slice(11);    // 'great'
u('Symfony is great')->slice(-5);    // 'great'

// уменьшает строку до длины, заданной в качестве аргумента (если она длиннее)
u('Lorem Ipsum')->truncate(3);             // 'Lor'
u('Lorem Ipsum')->truncate(80);            // 'Lorem Ipsum'
// второй аргумент - символ(ы), добавленные, когда строка урезается
// (общая длина включает в себя длину этого(их) символа(ов))
u('Lorem Ipsum')->truncate(8, '…');        // 'Lorem I…'
// если третий аргумент - false, последнее слово до обрезания остается, даже
// если это создает строку, больше описанной длины
u('Lorem Ipsum')->truncate(8, '…', false); // 'Lorem Ipsum'

New in version 5.1: Третий аргумент truncate() был представлен в Symfony 5.1.

// разбивает строку на строчки заданной длины
u('Lorem Ipsum')->wordwrap(4);             // 'Lorem\nIpsum'
// по умолчанию разбивает по свободным пространствам; передайте TRUE, чтобы разбивать независимо от этого
u('Lorem Ipsum')->wordwrap(4, "\n", true); // 'Lore\nm\nIpsu\nm'

// заменяет часть строки на заданное содержание:
// второй аргумент - местоположение, с которого начинается замена;
// третий аргумент - количество графем/кодовых точек, удаленных из строки
u('0123456789')->splice('xxx');       // 'xxx'
u('0123456789')->splice('xxx', 0, 2); // 'xxx23456789'
u('0123456789')->splice('xxx', 0, 6); // 'xxx6789'
u('0123456789')->splice('xxx', 6);    // '012345xxx'

// разбиывает строку на части длиной, заданной аргументом
u('0123456789')->chunk(3);  // ['012', '345', '678', '9']

// реверсирует порядок содержания строки
u('foo bar')->reverse(); // 'rab oof'
u('さよなら')->reverse(); // 'らなよさ'

New in version 5.1: Метод reverse() был представлен в Symfony 5.1.

Методы, добавленные ByteString

Эти методы доступны только для объектов ByteString:

// возвращает TRUE, если содержание строки является валидным содержанием UTF-8
b('Lorem Ipsum')->isUtf8(); // true
b("\xc3\x28")->isUtf8();    // false

Методы, добавленные CodePointString и UnicodeString

Эти методы доступны только для объектов CodePointString и UnicodeString:

// транслитерирует любоую строку в латинский алфавит, определенный шифрованием ASCII
// (не используйте этот метод для создания слаггера, так как данный компонент уже предоставляет
// слаггер, как объясняет дальше в статье)
u('नमस्ते')->ascii();    // 'namaste'
u('さよなら')->ascii(); // 'sayonara'
u('спасибо')->ascii(); // 'spasibo'

// возвращает массив с кодовой точкой или точками, хранящимися в заданном местоположении
// (кодовые точки 'नमस्ते' графемы = [2344, 2350, 2360, 2340]
u('नमस्ते')->codePointsAt(0); // [2344]
u('नमस्ते')->codePointsAt(2); // [2360]

Эквивалентность Юникода - это спецификация стандарта Юникод, по которой разные последовательности кодовых точек предоставляют один и тот же знак. Например, шведская буква å может быть одной кодовой точкой (U+00E5 = “маленькая латинская буква А с кольцом над ней”) или последовательностью двух кодовых точек (U+0061 = “маленькая латинская буква A” + U+030A = “комбинация с кольцом сверху”). Метод normalize() позволяет выбрать режим нормализации:

// эти зашифровывают букву как одну кодовую точку: U+00E5
u('å')->normalize(UnicodeString::NFC);
u('å')->normalize(UnicodeString::NFKC);
// эти зашифровывают букву как две кодовые точки: U+0061 + U+030A
u('å')->normalize(UnicodeString::NFD);
u('å')->normalize(UnicodeString::NFKD);

Слаггер

В некоторых контекстах, вроде URL и названий файлов/каталогов, небезопасно использовать любой символ Юникода. Слаггер преобразует заданную строку в другую строку, которая содержит только безопасные символы ASCII:

use Symfony\Component\String\Slugger\AsciiSlugger;

$slugger = new AsciiSlugger();
$slug = $slugger->slug('Wôrķšƥáçè ~~sèťtïñğš~~');
// $slug = 'Workspace-settings'

// вы также можете передать массив с дополнительными заменами символов
$slugger = new AsciiSlugger('en', ['en' => ['%' => 'percent', '€' => 'euro']]);
$slug = $slugger->slug('10% or 5€');
// $slug = '10-percent-or-5-euro'

// если для вашей локали не существует отображения символа (например, 'en_GB'), то будет использовано
// отображение символа родительской локали (т.e. 'en')
$slugger = new AsciiSlugger('en_GB', ['en' => ['%' => 'percent', '€' => 'euro']]);
$slug = $slugger->slug('10% or 5€');
// $slug = '10-percent-or-5-euro'

// для более динамичных замен, передайте замыкание PHP вместо массива
$slugger = new AsciiSlugger('en', function ($string, $locale) {
    return str_replace('❤️', 'love', $string);
});

New in version 5.1: Функция определения дополнительных замен была представлена в Symfony 5.1.

New in version 5.2: Функция использования замыкания PHP для определения замен была представлена в Symfony 5.2.

New in version 5.3: Функция резеврного использования отображения символа родительской локали была представлена в Symfony 5.3.

Разделитель между словами - по умолчанию дефис (-), но вы можете определить другой разделить как второй аргумент:

$slug = $slugger->slug('Wôrķšƥáçè ~~sèťtïñğš~~', '/');
// $slug = 'Workspace/settings'

Слаггер транслитерирует изначальную строку в латиницу до того, как применять любые другие преобразования. Локаль изначальной строки определяется автоматически, но вы можете ясно определить ее:

// сообщает слаггеру транслитерировать с корейского языка
$slugger = new AsciiSlugger('ko');

// вы можете переопределить локаль в качестве третьего необязательного параметра slug()
$slug = $slugger->slug('...', '-', 'fa');

В приложении Symfony, вам не нужно создавать слаггер самостоятельно. Благодаря автомонтированию сервисов, вы можете внедрить слаггер с подсказкой в аргументе сервис-конструктора с помощью SluggerInterface. Локаль внедренного слаггера будет той же, что и локаль запроса:

use Symfony\Component\String\Slugger\SluggerInterface;

class MyService
{
    private $slugger;

    public function __construct(SluggerInterface $slugger)
    {
        $this->slugger = $slugger;
    }

    public function someMethod()
    {
        $slug = $this->slugger->slug('...');
    }
}

Инфлектор

New in version 5.1: Функция инфлектор была представлена в Symfony 5.1.

В некоторых случаях, вроде генерирования и интроспекции кода, вам нужно преобразовывать слова в/из множественного/единственное число. Например, чтобы узнать свойство, асооциированное с методом adder, вы должны выполнить преобразование из множественного (метод addStories()) в единственное (свойство $story).

Большинство человеческих языков имеют простые правила множественных чисел, но в то же время они определяют много исключений. Например, общее правило в английском языке - добавлять s в конце слова (book -> books), но существует множество исключений даже для распространенных слов (woman -> women, life -> lives, news -> news, radius -> radii, и т.д.)

Этот компонент предоставляет класс EnglishInflector, чтобы уверенно преобразовывать английские слова в/из единственное/множественное число:

use Symfony\Component\String\Inflector\EnglishInflector;

$inflector = new EnglishInflector();

$result = $inflector->singularize('teeth');   // ['tooth']
$result = $inflector->singularize('radii');   // ['radius']
$result = $inflector->singularize('leaves');  // ['leaf', 'leave', 'leaff']

$result = $inflector->pluralize('bacterium'); // ['bacteria']
$result = $inflector->pluralize('news');      // ['news']
$result = $inflector->pluralize('person');    // ['persons', 'people']

Значение, возвращенное обоими методами, всегда являетя массивом, так как иногда невозможно определить уникальную единственную/множественную форму заданного слова.

Эта документация является переводом официальной документации Symfony и предоставляется по свободной лицензии CC BY-SA 3.0.