.hasSuffix

this is the examples for using hasSuffix

let plans = "Let's meet at the café"

// Case sensitive
print(plans.hasSuffix("Café"))
// Prints "false"

The Unicode-safe comparison matches Unicode scalar values rather than the code points used to compose them. The example below uses two strings with different forms of the "é" character—the first uses the composed form and the second uses the decomposed form.

// Unicode safe
let composedCafe = "café"
let decomposedCafe = "cafe\u{0301}"

print(plans.hasSuffix(composedCafe))
// Prints "true"
print(plans.hasSuffix(decomposedCafe))
// Prints "true"

but i don't understand ( \u{0301} ) why \u{0301} = é ?

What is the issue here you don't understand? It prints false because you have a typo there. Instead of hasSuffix("café") you write hasSuffix("Café") which will result to false.

No, not that part I don’t know how can i know that (e\u{0301}) it equal (è) ? in let decomposed and composed

No:

  • "Unicode scalar" values are code points.

  • Swift compares Strings by graphemes (Character by Character), not code points.

  • Swift treats composition forms as an implementation detail. They don't affect String comparisons.

...

You’re right, but the poster wasn’t the one who made that mistake.

You both realize he literally copied and pasted the official hasSuffix(_:) documentation, right? He wasn’t asking us to fix it, but just to explain this:

Are you familiar with inserting line breaks into a string with \n? In the same way, \u{x} inserts the Unicode scalar U+x at that point in the string. So "\u{41}" will be the same as "A" (which is code point U+0041).

• U+0065 is just an E (e)
• U+00E9 is a single thing that is an E with an acute accent (é)
• U+0301 is just an acute accent ( ́)

With that in mind, you can see that this...

let composedCafe = "caf\u{E9}" // As a single thing.
let decomposedCafe = "caf\u{65}\u{301}" // As two pieces.

...is the same as typing the same characters directly like this...

let composedCafe = "café" // As a single thing.
let decomposedCafe = "café" // As two pieces.

...and it makes sense that both composedCafe and decomposedCafe represent the same string, even though they have different underlying bytes.

More U+... numbers can be looked up at Unicode’s website here.

4 Likes

Excuse me?

Sorry. I wasn’t sure how to notate that the related response came later on after the next quotation, because it was directed at both. “...” was the best I could think of.

1 Like

Okay I see, at first glance I wasn't sure if this was an indirect facepalm of some sort, but now I see your point. Thank you for clarifying it to me. And yes I wasn't sure what the original question was all about and therefore couldn't provide any good answer in this thread.

I do think you both make a good case for improving the documentation you just tried to correct here.

You understand me, thanks
I am a beginner in swift, I read it but I don't know why it uses Unicode Scalar I think it's difficult to use.
I thank those who responded to me :blush:

I have to admit I wouldn't have expected the documentation could make such a fundamental mistake. Actually, two fundamental mistakes.

Fixed in https://github.com/apple/swift/pull/22056.

5 Likes

The only problem I have with that fix is that there aren't really "composed" and "decomposed" forms of a character (or a string) — in the Swift sense of Character or String. The Unicode normalization form is an implementation detail which the compiler (AFAIK) is not obligated to maintain one way or the other.

The "forms" here are really just alternate "spellings" of the string in source code. I'd suggest referring to this as "string literals written in different ways", or something like that.

Or do I have this wrong, and there is some implication about the normal form being used under the hood?

(@modyX, ignore us. I’m answering others here and it will get complicated fast.)

The fix is great.

String is obligated to preserve the same scalar sequence. If it did not, String.UnicodeScalarView, String.UTF8View, etc would all break.

Even if the entire API and implementation were overhauled in the future, there will always be access to preserved scalars for the text processing which needs it.

1 Like

Technically, this is unspecified, but I'm pretty strongly in favor of guaranteeing it, at least on a initializer-by-initializer basis (e.g. imagine a future putMeInNFC initializer).

Related, we should have lazily-normalized-scalar views for NFC, NFD, NFKC, and NFKD (and maybe FCC, with a compelling reason). This would allow the user can say something like myString.unicodeScalars.nfkd to get a BidirectionalCollection of Unicode.Scalar in NFKD, lazily normalizing segment-by-segment. This was discussed briefly in String case folding and normalization APIs and we'll likely revisit it after Swift 5.

1 Like

If there is more to say, let’s start a thread under “Evolution” or “Development”. This is under “Using Swift” and the original poster identified himself as a beginner. Let’s not scare him away with endless complicated internal details that are not relevant to him.

1 Like

I am not ignoring anybody. I see what you write but i am new in swift and in coding in general i have basics of java because of android. There is alot of things i don’t understand and I don’t want to ask because it will become distraction for me. I learn swift from apple books swift 4.2 so i have to ask in certain points. I don’t want to go into details
In the first i coped that code wrong that’s why the replier didn’t understand me and i sorry for that mistake

You did not make any mistake. We did. The only mistake was in our documentation that you were reading in the first place. We apologize for taking your thread on a tangent and causing further confusion. Feel free to ask any and all questions that come to mind. And also feel free to ignore anything of what we said that is just a distraction to you. Above all, know that you are welcome here.

1 Like

Thanks :slightly_smiling_face:, all I need a developer knows the basics well to ask him about what I don't understand it
.When he will be free and I will be thankful to him