Skip to main content

String trong Swift - phần 1



Biểu diễn các kí tự là vấn đề được đề cập đến đầu tiên khi các bạn tiếp cận một ngôn ngữ. Việc giao tiếp giữa máy chủ và client - cụ thể tại đây là thiết bị điện thoại đều được chuyển hóa qua dạng kí tự, ví dụ như response nhận lấy từ request thường thấy có dạng json.

Trong bài viết này, mình xin tổng hợp một vài cách thức cơ bản liên quan đến việc biểu diễn kí tự trên ngôn ngữ Swift và bài toán nhỏ để thực hành mà các bạn gặp phải trong lúc làm việc trong thực tế.

Và trong các bài viết sau, mình sẽ đề cập đến những kĩ thuật phức tạp như formating, comparing, sorting... 

Tất cả các ví dụ trong bài, mình sẽ sử dụng version mới nhất của Swift là 3.0.1

Để biểu diễn chuỗi kí tự trong Swift, ta sử dụng struct có tên là String để biểu diễn.

I - Initializing a String:

Có rất nhiều cách để khởi tạo một chuỗi

// Từ một chuỗi rỗng hoặc một chuỗi khác
var emptyString = ""
var stillEmpty = String()
let helloWorld = "Hello World!"

// Có thể tạo ra bằng cách lặp lại một chuỗi khác
let h = String(repeating:"01", count:3) //Output: 010101

// từ true/false - boolean
let a = String(true)

// Từ một kí tự
let b: Character = "A"          // Explicit type to create a Character
let c = String(b)               // from character "A"

// Từ giá trị số
let d = String(3.14)            // from Double "3.14"
let e = String(1000)            // from Int "1000"
let f = "Result = \(d)"         // Interpolation "Result = 3.14"
let g = "\u{2126}"              // Unicode Ohm sign

// Lấy từ một file
if let path = Bundle.main.path(forResource: "otherFile", ofType: "txt") {
  do {
    let content = try String(contentsOfFile: path, encoding: .utf8)
  } catch {
    print("Something went wrong")
  }
}


II - Strings are Value Types:

Nghĩa là trong phép gán, giá trị của nó được sao chép đến giá trị của biến String khác.

var aString = "Hello"
var bString = aString
print("\(aString)")     // "Hello"
bString += " World!"    // "Hello World!"

Testing String (Empty, Equality and Order):

// Để kiểm tra chuỗi đó là rỗng
emptyString.isEmpty     // true

// Sự giống nhau, một vài tài liệu tham khảo nói đến Unicode canonical equivalence,
// nghĩa là swift sẽ dùng định dạng Unicode của chuỗi để so sánh
let spain = "España"
let tilde = "\u{303}"
let country = "Espan" + "\(tilde)" + "a"
if country == spain {
  print("Matched!")       // "Matched!"
}

// So sánh dựa trên thứ tự:
if "aaa" < "bbb" {
  print("aaa is less than bbb")  // "aaa is less than bbb"
}

Suffix/prefix, upper/lower case

// Kiểm tra chuỗi bắt đầu hoặc kết thúc bằng một chuỗi khác
let line = "0001 Some test data here %%%%"
line.hasPrefix("0001")    // true
line.hasSuffix("%%%%")    // true

// Dạng viết hoa và viết thường của một chuỗi
let mixedCase = "AbcDef"
let upper = mixedCase.uppercased() // "ABCDEF"
let lower = mixedCase.lowercased() // "abcdef"

III - Views, Counting

Về bản chất, trong String, một chuỗi không phải là một tập hợp kí tự. Ví dụ bên dưới, bạn sẽ nhìn một sự khác biệt 


let cafe = "Cafe\u{301} du 🌍"
print(cafe)
// Prints "Café du 🌍

Chúng không biểu diễn 1-1 như các ngôn ngữ khác. Thay vào đó, String cung cấp nhiều hình thái cho những định dạng khác nhau bằng các thuộc tính bên trong.

Dạng biểu diễn - Character View: 

> A string’s characters property is a collection of extended grapheme clusters, which approximate human-readable characters.

print(cafe.characters.count)
// Prints "9"
print(Array(cafe.characters))
// Prints "["C", "a", "f", "é", " ", "d", "u", " ", "🌍"]"

Ta có thể nhìn thấy biểu hiện của chúng bằng mắt thường. Một kí tự biểu diễn trên có thể được tạo nên bởi nhiều kí tự Unicode.


Biểu diễn Unicode - Unicode Scalar View

> A string’s unicodeScalars property is a collection of Unicode scalar values, the 21-bit codes that are the basic unit of Unicode. Each scalar value is represented by a UnicodeScalar instance and is equivalent to a UTF-32 code unit.
print(cafe.unicodeScalars.count)
// Prints "10"
print(Array(cafe.unicodeScalars))
// Prints "["C", "a", "f", "e", "\u{0301}", " ", "d", "u", " ", "\u{0001F30D}"]"
print(cafe.unicodeScalars.map { $0.value })
// Prints "[67, 97, 102, 101, 769, 32, 100, 117, 32, 127757]"

Nó là một tập hợp kí tự được biểu diễn với giá trị 32bit

Biểu diễn 16bit - UTF-16 View

> A string’s utf16 property is a collection of UTF-16 code units, the 16-bit encoding form of the string’s Unicode scalar values. Each code unit is stored as a UInt16 instance.
print(cafe.utf16.count)
// Prints "11"
print(Array(cafe.utf16))
// Prints "[67, 97, 102, 101, 769, 32, 100, 117, 32, 55356, 57101]"
Chú ý: NSString API cũng sử dụng định dạng khi truy cập các kí tự
let nscafe = cafe as NSString
print(nscafe.length)
// Prints "11"
print(nscafe.character(at: 3))
// Prints "101"

Biểu diễn 8bit - UTF-8 View

> A string’s utf8 property is a collection of UTF-8 code units, the 8-bit encoding form of the string’s Unicode scalar values. Each code unit is stored as a UInt8 instance.
print(cafe.utf8.count)
// Prints "14"
print(Array(cafe.utf8))
// Prints "[67, 97, 102, 101, 204, 129, 32, 100, 117, 32, 240, 159, 140, 141]"
Chú ý: C API sử dụng định dạng này để truy cập các phần tử bên trong chuỗi.
let cLength = strlen(cafe)
print(cLength)
// Prints "14"

IV - Bài toán thực tế:

> Kiểm tra password mà người dùng nhập vào có hợp lệ hay ko? Với password hợp lệ có ít nhất 6 kí tự và thuộc những kí tự hợp lệ cho trước. 

Với những ngôn ngữ khác như PHP, Java Script, chúng nó sẽ sử dụng Regular Expression.
Nhưng tại đây, mình sẽ sử dụng những kiến thức cơ bản về String bên trên giải quyết bài toán trên.

Ý tưởng: 

Mình sẽ sử dụng định dạng Unicode của String vì chúng có miền giá trị 32bit, sẽ xử lý bài toán một cách tổng quát cho bất kì chuỗi kí tự nào người dùng nhập từ bàn phím.

Kèm theo [bảng mã Unicode](http://www.codetable.net/unicodecharacters?page=1) để xác định miền giá trị cho những kí tự hợp lệ.

enum ValidatedStatus {
    case notEnoughForLength
    case invalidFormat
    case valid
}
func validate(password:String) -> ValidatedStatus {
    // I choose the range of Unicode value from 32(!) to 126(~) to be validated range
    let minimalValue:UInt32 = 32
    let maximalValue:UInt32 = 126
  
    let minimalLength = 6
  
    let unicodeView = password.unicodeScalars
  
    if unicodeView.count < minimalLength {
        return .notEnoughForLength
    }
  
    for char in unicodeView {
        if char.value < minimalValue || char.value > maximalValue {
            return .invalidFormat
        }
    }
  
    return .valid
}

V - Kết luận: 

  • Độ dài của chuỗi và định dạng của chuỗi sẽ liên quan chặt chễ đến nhau.
  • Với từng bài toán cụ thể, ta sẽ sử dụng định dạng của chuỗi cho phù hợp.


VI - Tham khảo:

  1. https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html
  2. https://developer.apple.com/reference/swift/string
  3. https://useyourloaf.com/blog/swift-string-cheat-sheet/



Mình sẽ luôn luôn cập nhập thêm kiến thức về String tại đây

Comments

Popular posts from this blog

Tài liệu và hướng dẫn học Python

Để tiết kiệm thời gian, tốt nhất là đi học PyMI Updated: 130617 Sau đây là các tài liệu khuyên dùng: Vì nhiều lý do, nên học python2.7 tại thời điểm hiện tại (giờ là tháng 6/2013 - muốn biết tại sao thì tự tìm hiểu) python 3.5+ (giờ là tháng 2/2017) Chuẩn bị: 1. biết bật tắt máy 2. biết cài python 3. tập gõ 10 ngón - gõ 2 ngón hay 1 ngón cũng không sao, nhưng 10 ngón là cách dễ nhất để gõ nhanh nhất. Tài liệu - Nên dùng tài liệu tại trang chủ của Python làm chính, tham khảo thêm các tài liệu khác tại http://www.familug.org/2016/12/free-ebook.html Căn bản, mới học 1.1 Python PyMI.vn https://pymi.vn/tutorial/ 1.2. Python offical tutorial kết hợp làm bài tập trên HackerRank  (đề bài bằng tiếng Anh, nhưng Google translate 1 lúc cũng ra vì có nhiều ví dụ mẫu đi kèm). Học viên của Pymi.vn có rất nhiều học viên đã tự học với Learn Python the hard way nhưng chưa thấy ai thành công cả. Hai link dưới nên đọc sau khi đã nắm được những phần cơ bản của ngôn ngữ pytho...

The PyMiers

New FAMILUG