0

In javascript Infinity is always larger than any other number except itself, while -Infinity is always smaller. What is an analogue of that for characters, i.e. what are the value of a string c for which c.localCompare(anyString) would always return (+/-)1 respectively (obviously except when c === anyString)?

In practice this will be used to sort objects based on 2 flags and the groupName property, which will be keyed in by users into another piece of software under input validation constraints, so won't be an empty string. (I would need to check to see if someone could 'attack' the script by pasting lots of 0xFFFF into name prompt.)

If something like Infinity existed, the callback for sort() would look like this:

(n1, n2) =>
  (n1.flag1 ? plusCharInfinity :
    n1.flag2 ? minusCharInfinity :
      n1.groupName).localeCompare(
        n2.flag1 ? plusCharInfinity :
          n2.flag2 ? minusCharInfinity :
            n2.groupName)

I.e. if flag1 === true then demote to the bottom; if flag2 === true - promote to the top; otherwise use the given groupName value.

biinster
  • 45
  • 9
  • 5
    There is no direct analog. For characters, you have to account for the fact that there are code points which require a pair of UTF-16 characters to be represented, and apparently ChatGPT does not know that. – Pointy Mar 30 '23 at 01:32
  • 2
    Also strings can be of any length. There is a largest possible UTF-32 codepoint, but a string of 100 of them is greater than a string of 99. I don't think what you're asking for is possible. – Pointy Mar 30 '23 at 01:35
  • 4
    The empty string provides one end. The infinite string (consisting of `0xFFFF`s only) provides the other end, but cannot be constructed. – Bergi Mar 30 '23 at 01:35
  • OP does specify `except when c === anyString` @pilchard – Toastrackenigma Mar 30 '23 at 01:39
  • 1
    @Toastrackenigma that's fair, if their use case doesn't require empty strings. My point was it may be useful as a lower bound, but isn't analogous to `-Infinity` rather closer to `Number.MIN_SAFE_INTEGER` – pilchard Mar 30 '23 at 01:42
  • Yeah, that's also a fair point @pilchard. I don't think such an analogous value exists however. – Toastrackenigma Mar 30 '23 at 01:51
  • 2
    Why call an unnecessary function (localeCompare) when you already know what the return value should be, in the case that flags are set. – James Mar 30 '23 at 02:46
  • Thanks for the lower bound idea, @Bergi and @pilchard! – biinster Mar 30 '23 at 03:29

2 Answers2

2

There's no directly analogous values for strings, or at least none that I could easily find in the spec.

Lower Bound

The empty string, "", works well as the lower bound, however as @pilchard points out, it's also a value that you might commonly have, so it's not as safe as e.g. -Infinity which is always even lower than any actual valid non-infinity number.

stringToCompare.localeCompare("");

Higher Bound

The high bound is harder to construct. Theoretically, you'd need to have the maximum length string, with every character as the highest value, and to wit, here are some approaches you could try to get that value:

  • You could try to override the getter for a specific string's length property, to pretend you have a really big string. However, the prototype is frozen in most engines, and you're not allowed to override it.

  • The JavaScript spec defines a maximum size for strings as 253-1 elements, which weighs in as requiring 16,384TiB of storage, and thus is impossible to construct.

    However most browsers limit this to a much smaller number (one which can actually fit in the RAM that we have today): 32-bit Chrome: ~512Mib, 64-bit Chrome: ~1Gib, Firefox: ~2Gib and Safari: ~4Gib. There are ways to check that length and construct such a string, but it would be quite the waste of memory, and not particularly performant.

But, there is a simpler solution. If you're OK with not having a fixed highest value, you could always construct the "higher" string each time you need to do a comparison.

JavaScript represents characters as 16-bit numbers, making the biggest possible character \uffff. If we construct a string that is the same as the original string, but which has this character at the beginning, then this new string will always be larger than the original string:

stringToCompare.localeCompare(`\uffff${stringToCompare}`);
Toastrackenigma
  • 7,604
  • 4
  • 45
  • 55
-1

As others have pointed out in the comments, it's not possible to create strings which exist outside the range of valid string code points in order to enforce the relationships described.

However, if you simply want to implement deterministic sort cases using the String.prototype.localeCompare() API (which is implementation-defined by the way), you can implement it using custom objects. Here is an example:

const smallest = {
  localeCompare(that) {
    return Object.is(this, that) ? 0 : -1;
  },
};

const largest = {
  localeCompare(that) {
    return Object.is(this, that) ? 0 : 1;
  },
};

console.log(smallest.localeCompare(smallest)); // 0
console.log(largest.localeCompare(largest)); // 0

console.log(smallest.localeCompare(largest)); // -1
console.log(smallest.localeCompare("")); // -1
console.log(smallest.localeCompare("zzzzzzzzzz")); // -1
// etc.

console.log(largest.localeCompare(smallest)); // 1
console.log(largest.localeCompare("")); // 1
console.log(largest.localeCompare("zzzzzzzzzz")); // 1
// etc.

Code in TS Playground

jsejcksn
  • 27,667
  • 4
  • 38
  • 62
  • This doesn’t really work, because it’s inconsistent with `"".localeCompare(smallest)`. – Ry- Mar 31 '23 at 23:09
  • [^](https://stackoverflow.com/questions/75883404/an-analogue-for-infinity-for-characters-in-javascript/75883557?noredirect=1#comment133881594_75883557) @Ry- The [original question](https://stackoverflow.com/revisions/75883404/1) only asked about one-way usage, and this answer is a response to that. It appears that the question criteria was changed. – jsejcksn Apr 01 '23 at 00:22