0

I search for a solution to sort an array only that the lower-case are first. I know the order from regex [A-Za-z0-9]. I like the order [a-zA-Z0-9]. case-insensitive sort is not a solution for this.

  1. Normaly sort from scandir():
    • A001.TXT
    • B002.TXT
    • C003.TXT
    • X004.TXT
    • Y005.txt
    • Z006.TXT
    • a001.txt
    • b002.TXT
    • c003.txt
    • x004.txt
    • y005.TXT
    • z006.txt
    • 0001.TXT
    • 1001.txt
    • 2001.TXT
  2. I like this sort:
    • a001.txt
    • b002.TXT
    • c003.txt
    • x004.txt
    • y005.TXT
    • z006.txt
    • A001.TXT
    • B002.TXT
    • C003.TXT
    • X004.TXT
    • Y005.txt
    • Z006.TXT
    • 0001.TXT
    • 1001.txt
    • 2001.TXT
2
  • You can use usort() and implement any comparation function You like. Commented Jun 9, 2020 at 16:47
  • ideally all file extensions in a directory should all be one case -- Since technically speaking a001.txt and a001.TXT are two separate files with the same naming convention prior to the extension. 1) this would solve your issue and 2) it will alleviate more confusion in the future should two files be named the same thing with different cases on the extension. Also, just in case you are using uppercase and lowercase of the same extension to differentiate between files - Don't. This is also bad practice and a more thorough naming convention should be established. Commented Jun 9, 2020 at 16:48

2 Answers 2

1

We can try using usort() here with a custom comparator function:

$arr = array(...);
function getOrder($input) {
    $order = 4;
    if (preg_match("/^[a-z]/", $input)) {
        $order = 1;
    }
    else if (preg_match("/^[A-Z]/", $input)) {
        $order = 2;
    }
    else if (preg_match("/^[0-9]/", $input)) {
        $order = 3;
    }
    else {
        $order = 4;
    }

    return $order;
}

usort($arr, function($a, $b) {
    $a_order = getOrder($a);
    $b_order = getOrder($b);

    if ($a_order == $b_order) {
        return strcmp($a, $b);
    }

    if ($a_order < $b_order) {
        return -1;
    }
    else {
        return 1;
    }
});

$print_r($arr);

This prints:

Array
(
    [0] => a001.txt
    [1] => b002.TXT
    [2] => c003.txt
    [3] => x004.txt
    [4] => y005.TXT
    [5] => z006.txt
    [6] => A001.TXT
    [7] => B002.TXT
    [8] => C003.TXT
    [9] => X004.TXT
    [10] => Y005.txt
    [11] => Z006.TXT
    [12] => 0001.TXT
    [13] => 1001.txt
    [14] => 2001.TXT
)

The strategy here is to use the getOrder() function to determine whether a filename begin with a lowercase, uppercase, or number. For each of these cases, we assign a priority, increasing in that order. Then, in the lambda comparator function used with usort(), we compare the priorities of the two incoming filenames. Note that for the case where two filenames happen to start with the same type (e.g. both lowercase), we fall back to strcmp() to determine which comes first.

Sign up to request clarification or add additional context in comments.

2 Comments

aha. so it works usort(). there is no pre-built function available for this? I like a PHP pre-built func like regexsort($array, '[a-zA-Z0-9]'). And than i will edit my question to regexsort($array, '[0-9a-zA-Z]'), because origin regex is [0-9A-Za-z] like ASCII order.
@Malama You actually want reverse ASCII order based on the first letter class (digit, uppercase, lowercase), but within each class, it should be sorted ascending by ASCII.
0

Use array_multisort() and make 3 separate evaluations.

  1. Make any element empty if it starts with a letter (this will put all letter-prefixed values first)
  2. Make any element empty if it starts with a lowercase letter (this will put all lowercase-prefixed values before all uppercase-prefixed values)
  3. Sort normally.

Code: (Demo)

array_multisort(
    preg_replace('/^[a-z].*/i', '', $array),  // make values which start with a letter -> empty
    preg_replace('/^[a-z].*/', '', $array),   // make values which start with a lowercase letter -> empty
    $array                                    // sort all normally
);
var_export($array);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.