Coder Social home page Coder Social logo

yiisoft / strings Goto Github PK

View Code? Open in Web Editor NEW
48.0 23.0 15.0 341 KB

String helper methods and an inflector

Home Page: https://www.yiiframework.com/

License: BSD 3-Clause "New" or "Revised" License

PHP 100.00%
string yii3 inflector pattern-matching numerical hacktoberfest

strings's Introduction

Yii Strings


Latest Stable Version Total Downloads Build Status Scrutinizer Code Quality Code Coverage Mutation testing badge static analysis type-coverage

The package provides:

  • StringHelper that has static methods to work with strings;
  • NumericHelper that has static methods to work with numeric strings;
  • Inflector provides methods such as toPlural() or toSlug() that derive a new string based on the string given;
  • WildcardPattern is a shell wildcard pattern to match strings against;
  • CombinedRegexp is a wrapper that optimizes multiple regular expressions matching and MemoizedCombinedRegexp is a decorator that caches results of CombinedRegexp to speed up matching.

Requirements

  • PHP 8.0 or higher.
  • mbstring PHP extension.

Installation

composer require yiisoft/strings

StringHelper usage

String helper methods are static so usage is like the following:

echo \Yiisoft\Strings\StringHelper::countWords('Strings are cool!'); // 3

Overall the helper has the following method groups.

Bytes

  • byteLength
  • byteSubstring

File paths

  • baseName
  • directoryName

Substrings

  • substring
  • replaceSubstring
  • startsWith
  • startsWithIgnoringCase
  • endsWith
  • endsWithIgnoringCase
  • findBetween
  • findBetweenFirst
  • findBetweenLast

Truncation

  • truncateBegin
  • truncateMiddle
  • truncateEnd
  • truncateWords
  • trim
  • ltrim
  • rtrim

Counting

  • length
  • countWords

Lowercase and uppercase

  • lowercase
  • uppercase
  • uppercaseFirstCharacter
  • uppercaseFirstCharacterInEachWord

URL friendly base64

  • base64UrlEncode
  • base64UrlDecode

Other

  • parsePath
  • split

NumericHelper usage

Numeric helper methods are static so usage is like the following:

echo \Yiisoft\Strings\NumericHelper::toOrdinal(3); // 3rd

The following methods are available:

  • toOrdinal
  • normalize
  • isInteger

Inflector usage

echo (new \Yiisoft\Strings\Inflector())
    ->withoutIntl()
    ->toSlug('Strings are cool!'); // strings-are-cool

Overall the inflector has the following method groups.

Plurals and singulars

  • toPlural
  • toSingular

Transliteration

  • toTransliterated

Case conversion

  • pascalCaseToId
  • toPascalCase
  • toCamelCase

Words and sentences

  • toSentence
  • toWords
  • toHumanReadable

Classes and database tables

  • classToTable
  • tableToClass

URLs

  • toSlug

WildcardPattern usage

WildcardPattern allows a simple POSIX-style string matching.

use \Yiisoft\Strings\WildcardPattern;

$startsWithTest = new WildcardPattern('test*');
if ($startsWithTest->match('testIfThisIsTrue')) {
    echo 'It starts with "test"!';
}

The following characters are special in the pattern:

  • \ escapes other special characters if usage of escape character is not turned off.
  • * matches any string, including the empty string, except delimiters (/ and \ by default).
  • ** matches any string, including the empty string and delimiters.
  • ? matches any single character.
  • [seq] matches any character in seq.
  • [a-z] matches any character from a to z.
  • [!seq] matches any character not in seq.
  • [[:alnum:]] matches POSIX style character classes.

ignoreCase() could be called before doing a match() to get a case-insensitive match:

use \Yiisoft\Strings\WildcardPattern;

$startsWithTest = new WildcardPattern('test*');
if ($startsWithTest
    ->ignoreCase()
    ->match('tEStIfThisIsTrue')) {
    echo 'It starts with "test"!';
}

CombinedRegexp usage

CombinedRegexp optimizes matching multiple regular expressions.

use \Yiisoft\Strings\CombinedRegexp;

$patterns = [
    'first',
    'second',
    '^a\d$',
];
$regexp = new CombinedRegexp($patterns, 'i');
$regexp->matches('a5'); // true – matches the third pattern
$regexp->matches('A5'); // true – matches the third pattern because of `i` flag that is applied to all regular expressions
$regexp->getMatchingPattern('a5'); // '^a\d$' – the pattern that matched
$regexp->getMatchingPatternPosition('a5'); // 2 – the index of the pattern in the array
$regexp->getCompiledPattern(); // '~(?|first|second()|^a\d$()())~'

MemoizedCombinedRegexp usage

MemoizedCombinedRegexp caches results of CombinedRegexp in memory. It is useful when the same incoming string are matching multiple times or different methods of CombinedRegexp are called.

use \Yiisoft\Strings\CombinedRegexp;
use \Yiisoft\Strings\MemoizedCombinedRegexp;

$patterns = [
    'first',
    'second',
    '^a\d$',
];
$regexp = new MemoizedCombinedRegexp(new CombinedRegexp($patterns, 'i'));
$regexp->matches('a5'); // Fires `preg_match` inside the `CombinedRegexp`.
$regexp->matches('first'); // Fires `preg_match` inside the `CombinedRegexp`.
$regexp->matches('a5'); // Does not fire `preg_match` inside the `CombinedRegexp` because the result is cached.
$regexp->getMatchingPattern('a5'); // The result is cached so no `preg_match` is fired.
$regexp->getMatchingPatternPosition('a5'); // The result is cached so no `preg_match` is fired.

// The following code fires only once matching mechanism.
if ($regexp->matches('second')) {
    echo sprintf(
        'Matched the pattern "%s" which is on the position "%s" in the expressions list.',
        $regexp->getMatchingPattern('second'),
        $regexp->getMatchingPatternPosition('second'),
    );
}

Testing

Unit testing

The package is tested with PHPUnit. To run tests:

./vendor/bin/phpunit

Mutation testing

The package tests are checked with Infection mutation framework with Infection Static Analysis Plugin. To run it:

./vendor/bin/roave-infection-static-analysis-plugin

Static analysis

The code is statically analyzed with Psalm. To run static analysis:

./vendor/bin/psalm

Code style

Use Rector to make codebase follow some specific rules or use either newest or any specific version of PHP:

./vendor/bin/rector

Dependencies

Use ComposerRequireChecker to detect transitive Composer dependencies.

License

The Yii Strings is free software. It is released under the terms of the BSD License. Please see LICENSE for more information.

Maintained by Yii Software.

Support the project

Open Collective

Follow updates

Official website Twitter Telegram Facebook Slack

strings's People

Contributors

arhell avatar arogachev avatar dependabot-preview[bot] avatar dependabot[bot] avatar desure85 avatar devanych avatar fantom409 avatar hiqsol avatar kamarton avatar machour avatar mapeveri avatar olegbaturin avatar romkatsu avatar roxblnfk avatar salehhashemi1992 avatar samdark avatar sankaest avatar soodssr avatar stylecibot avatar terabytesoftw avatar tigrov avatar viktorprogger avatar vjik avatar xepozz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

strings's Issues

[enh] Proposal to add class StringObject

I propose to add class StringObject. Then it will be possible to manipulate strings in object-oriented style:

$baseWord = new StringObject('soft', 'UTF-8');

$projectName = $baseWord
   ->preprend('yii')
   ->addWord('project')
   ->upperCaseEveryWord();

$projectNameWordsCount = $projectName->wordsCount();

Then we can make class StringHelper a wrapper over class StringObject. For example:

class StringHelper
{
    public static function createObject(string $string, string $encoding = null): StringObject
    {
        return new StringObject($string, $encoding);
    }

    public static function wordsCount(string $string, string $encoding = null): int
    {
        return static::createObject($string, $encoding)->wordsCount();
    }
}

Redesign Inflector to be non-static

Having a static class that has configuration isn't good since it could be affected from many places. Thus inflector should be redesigned to be non-static.

truncate begin

StringHelper::truncateBegin() function to cut off the beginning of text content.

use case:

// sms sent to …234.
echo 'sms sent to ' . StringHelper::truncateBegin($model->phone, 3). '.';
Q A
Version 3.0.x-dev
PHP version -
Operating system -

Dependabot can't resolve your PHP dependency files

Dependabot can't resolve your PHP dependency files.

As a result, Dependabot couldn't update your dependencies.

The error Dependabot encountered was:

Your requirements could not be resolved to an installable set of packages.
  Problem 1
    - Installation request for yiisoft/strings No version set (parsed as 1.0.0) -> satisfiable by yiisoft/strings[No version set (parsed as 1.0.0)].
    - yiisoft/arrays 3.0.x-dev requires yiisoft/strings ^3.0@dev -> satisfiable by yiisoft/strings[3.0.x-dev].
    - yiisoft/var-dumper 3.0.x-dev requires yiisoft/arrays ^3.0@dev -> satisfiable by yiisoft/arrays[3.0.x-dev].
    - Can only install one of: yiisoft/strings[3.0.x-dev, No version set (parsed as 1.0.0)].
    - Installation request for yiisoft/var-dumper ^3.0@dev -> satisfiable by yiisoft/var-dumper[3.0.x-dev].

If you think the above is an error on Dependabot's side please don't hesitate to get in touch - we'll do whatever we can to fix it.

View the update logs.

Benchmark if mb_str_starts_with / mb_str_ends_with are worth it for PHP 8

Benchmark the following against current variant under PHP 8 / PHP 7:

public static function startsWith(string $input, ?string $with): bool
{
    if (function_exists('mb_str_starts_with')) {
        return mb_str_starts_with($input, $with);
    }
    
    $bytes = self::byteLength($with);
    if ($bytes === 0) {
        return true;
    }

    return strncmp($input, $with, $bytes) === 0;
}

If it's any better, apply the change.

Dependabot can't resolve your PHP dependency files

Dependabot can't resolve your PHP dependency files.

As a result, Dependabot couldn't update your dependencies.

The error Dependabot encountered was:

Your requirements could not be resolved to an installable set of packages.
  Problem 1
    - Installation request for yiisoft/strings No version set (parsed as 1.0.0) -> satisfiable by yiisoft/strings[No version set (parsed as 1.0.0)].
    - yiisoft/arrays 3.0.x-dev requires yiisoft/strings ^3.0@dev -> satisfiable by yiisoft/strings[3.0.x-dev].
    - yiisoft/var-dumper 3.0.x-dev requires yiisoft/arrays ^3.0@dev -> satisfiable by yiisoft/arrays[3.0.x-dev].
    - Can only install one of: yiisoft/strings[3.0.x-dev, No version set (parsed as 1.0.0)].
    - Installation request for yiisoft/var-dumper ^3.0@dev -> satisfiable by yiisoft/var-dumper[3.0.x-dev].

If you think the above is an error on Dependabot's side please don't hesitate to get in touch - we'll do whatever we can to fix it.

View the update logs.

New methods reverse and containsAny

What do you think about this two new methods?

StringHelper::containsAny('aeiou', 'a');  // true
StringHelper::containsAny('aeiou', ['ab', 'efg']); // false
StringHelper::containsAny('aeiou', ['eio', 'foo', 'z']); // true

And

StringHelper::reverse('foo bar'); // 'rab oof'

If they agree, I could send a PR.

New method `StringHelper::explode()`

Is that method usable?

/**
 * Split a string by separator.
 *
 * Differences from `explode()`:
 * - if `$separator` is an empty string, then split `$string` to chars
 * - if `$limit` less than -1, then split chunks at end
 *
 * @param string $separator The boundary string, '' - split a string to chars
 * @param string $string The string to split
 * @param int|null $limit Limit of chunks, NULL - no limit
 * @return array
 */
public static function explode(string $separator, string $string, int $limit = null): array
{
    if (\in_array($limit, [0, 1, -1], true)) {
        return [$string];
    }

    $chunks = $separator === '' ? \str_split($string) : \explode($separator, $string);

    if ($limit === null) {
        return $chunks;
    }

    $cnt = \count($chunks);
    if ($limit > 0) {
        if ($cnt > $limit) {
            $tail = \implode($separator, \array_slice($chunks, $limit - 1));
            \array_splice($chunks, $limit - 1, $cnt, $tail);
            
        }
    } else {
        if ($cnt + $limit > 0) {
            $tail = \implode($separator, \array_slice($chunks, 0, $limit + 1));
            \array_splice($chunks, 0, $limit + 1, $tail);
        }
        $chunks = \array_reverse($chunks);
    }

    return $chunks;
}

Usage example:

StringHelper::explode('', 'abc'); // ['a', 'b', 'c']
StringHelper::explode('\\', 'test\foo\bar\baz'); // ['test', 'foo', 'bar', 'baz']
StringHelper::explode('\\', 'test\foo\bar\baz', 2); // ['test', 'foo\bar\baz']
StringHelper::explode('\\', 'test\foo\bar\baz', -2); // ['baz', 'test\foo\bar']
StringHelper::explode('\\', 'test\foo\bar\baz', -3); // ['baz', 'bar', 'test\foo']

update irc link

What steps will reproduce the problem?

What is the expected result?

What do you get instead?

Additional info

Q A
Version 1.0.?
PHP version
Operating system

truncateMiddle improvements

I think truncateMiddle function (also truncateBegin and truncateCharacters) should have a different behavior.

We need to set the limit of the total string length, which includes the length of the separator.
For example:
original string 0123456789

truncateMiddle ('123456789', 8, '...');

As a result, we should get 123...89 or 12...789, and not 1234...6789 (11 symbols)

I also think that the function should first crop whitespace from the edges, and only then cut the content from the middle if necessary

add extended trim

public static function trim(string $str): string
{
    return trim($str, " \t\n\r\0\x0B\xC2\xA0\xEF\xBB\xBF");
}

Two files into separate package?

Why loading helpers as separate package - ? It's just two files ..
Will all helpers become separate packages now ? - ArrayHelper, FileHelper, ... ?

Is it to allow standalone usages for non Yii-framework folks?
It looks again like mimicking the symfony way - just to collect downloading statistics ...

update links

What steps will reproduce the problem?

http=>https

Redesign Inflector APIs

Resulting from the issue yiisoft/yii2#17150 I was writing some test cases for the Inflector methods for converting between camel case, words, ids, and I found that these methods result in quite inconsistent output on inputs that are not 100% simple and straight forward.

I think we should refactor these and get more clearly defined behavior + test coverage to make sure they work as intended.

I also found https://github.com/yiisoft/yii-core/issues/76 which seems related.
See also yiisoft/yii2#8604

Inflector::slug() delimiter syntax (merged words)

What steps will reproduce the problem?

It is more logical to assume that whatever is not convertible (special characters) is replaced by a separator character. In their current form, the words are merged.

What is the expected result?

'remove.!?[]{}…symbols' => 'remove-symbols',

What do you get instead?

'remove.!?[]{}…symbols' => 'removesymbols',

Q A
Yii version 3.0.x-dev
PHP version -
Operating system -

BaseInflector::id2camel() does not work for upper case words

What steps will reproduce the problem?

yiisoft/yii2-gii uses BaseInflector::id2camel() to generate class names but, when getting upper case table names from db like MY_TABLE, id2camel() does not work properly.

If it is ok, I can do a PR adding strtolower() inside ucwords().

What is the expected result?

id2camel('MY_TABLE', '_') // MyTable

What do you get instead?

id2camel('MY_TABLE', '_') // MYTABLE

Additional info

Q A
Yii version 2.0.15.1
PHP version 7.1.17
Operating system Win10

Incorrect pluralization of words ending in "ion"

What steps will reproduce the problem? Pluralize a word ending in "ion", e.g.

$plural = $inflector->toPlural('nation');

What is the expected result?

$plural === 'nations';

What do you get instead?

$plural === 'natia';

Additional info

Q A
Version dev-master
PHP version 8.2
Operating system Ubuntu

Documentation

I think It's better to have more documentation in this package.
I know there is enough phpdoc in file. by the way always people look for references

stringhelper truncate methods with default horizontal ellipsis postfix

I suggests

like as css, use horizontal ellipsis (…) for default truncate postfix character.

public static function truncateCharacters(string $string, int $length, string $suffix = '...', string $encoding = null): string

public static function truncateWords(string $string, int $count, string $suffix = '...'): string

Q A
Version 3.0.x-dev
PHP version -
Operating system -

Formatter feature request (text limit / word wrap)

I do not have concept to implement this thing, but I think that it can be extension to asText formatter method.

First, there are a few methods of word wrapping:

  • Strict (as much as possible characters, can break the word)
  • Word rounded up (include last word that reach the limit)
  • Word rounded down (include last word before reach the limit)

I want use word wrapping to limit text.
I know that I should use substr, but this method will break last word.
There is also wordwrap, but first it does have third wrapping method, and secondly it only insert break line character.

This feature can be used in:

  • DataGrid columns and DetailView to display first few words of content,
  • Headers on page and page title, when it use some field that can be too long. (For example "question content" on "question update page",

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.