Chuỗi Python

Python có một lớp chuỗi tích hợp tên là "str" với nhiều tính năng tiện dụng (có một mô-đun cũ hơn tên là "string" mà bạn không nên sử dụng). Hằng chuỗi có thể nằm trong dấu nháy kép hoặc dấu nháy đơn, mặc dù dấu ngoặc đơn thường được dùng hơn. Các ký tự thoát dấu gạch chéo ngược hoạt động theo cách thông thường trong cả giá trị cố định dấu ngoặc đơn và giá trị cố định kép - ví dụ: \n \' \". Giá trị cố định dạng chuỗi kép có thể chứa dấu ngoặc đơn mà không phức tạp (ví dụ: "Tôi không làm việc này") và tương tự như vậy, chuỗi dấu ngoặc đơn có thể chứa dấu ngoặc kép. Giá trị cố định dạng chuỗi có thể kéo dài nhiều dòng, nhưng phải có dấu gạch chéo ngược \ ở cuối mỗi dòng để thoát dòng mới. Giá trị cố định kiểu chuỗi nằm trong dấu ngoặc kép """ hoặc """ có thể kéo dài nhiều dòng văn bản.

Các chuỗi trong Python "không thể thay đổi" nghĩa là không thể thay đổi sau khi tạo (các chuỗi Java cũng sử dụng kiểu bất biến này). Vì chuỗi không thể thay đổi được, nên chúng ta tạo chuỗi *mới* khi biểu diễn các giá trị đã tính. Vì vậy, ví dụ: biểu thức ('hello' + 'there') nhận 2 chuỗi "hello" và "there" rồi tạo một chuỗi mới "hellothere".

Bạn có thể truy cập các ký tự trong một chuỗi bằng cú pháp [ ] tiêu chuẩn, và giống như Java và C++, Python sử dụng phương thức lập chỉ mục dựa trên số không, vì vậy nếu s là 'hello' s[1] là 'e'. Nếu chỉ mục nằm ngoài giới hạn của chuỗi, thì Python sẽ đưa ra lỗi. Kiểu Python (không giống như Perl) sẽ tạm dừng nếu không biết cần làm gì, thay vì chỉ tạo một giá trị mặc định. Cú pháp "Lát cắt" hữu ích (bên dưới) cũng dùng để trích xuất bất kỳ chuỗi con nào từ một chuỗi. Hàm len(string) trả về độ dài của một chuỗi. Cú pháp [ ] và hàm len() thực sự hoạt động trên mọi loại chuỗi – chuỗi, danh sách, v.v. Python cố gắng đảm bảo các hoạt động của mình hoạt động nhất quán trên nhiều loại. Người mới mới sử dụng Python: đừng sử dụng "len" làm tên biến để tránh chặn hàm len(). Toán tử "+" có thể nối hai chuỗi. Lưu ý trong mã bên dưới rằng các biến không được khai báo trước – bạn chỉ cần gán cho các biến đó và tiếp tục.

  s = 'hi'
  print(s[1])          ## i
  print(len(s))        ## 2
  print(s + ' there')  ## hi there

Không giống như Java, dấu "+" không tự động chuyển đổi số hoặc các kiểu khác thành dạng chuỗi. Hàm str() chuyển đổi các giá trị thành dạng chuỗi để có thể kết hợp với các chuỗi khác.

  pi = 3.14
  ##text = 'The value of pi is ' + pi      ## NO, does not work
  text = 'The value of pi is '  + str(pi)  ## yes

Đối với số, các toán tử chuẩn +, /, * hoạt động theo cách thông thường. Không có toán tử ++, nhưng các +=, -=, v.v. vẫn hoạt động. Nếu bạn muốn chia số nguyên, sử dụng 2 dấu gạch chéo - ví dụ: 6 // 5 là 1

Hàm "print" thường in một hoặc nhiều mục python theo sau là một dòng mới. Giá trị cố định dạng chuỗi "thô" có tiền tố "r" và chuyển tất cả các ký tự đi qua mà không cần xử lý đặc biệt dấu gạch chéo ngược, vì vậy r'x\nx' được đánh giá là chuỗi có độ dài 4 "x\nx". "print" có thể mất một số đối số để thay đổi cách in mọi thứ (xem định nghĩa hàm in python.org) như đặt "kết thúc" thành "" để không còn in một dòng mới sau khi in xong tất cả các mục.

  raw = r'this\t\n and that'

  # this\t\n and that
  print(raw)

  multi = """It was the best of times.
  It was the worst of times."""

  # It was the best of times.
  #   It was the worst of times.
  print(multi)

Phương thức chuỗi

Sau đây là một số phương thức chuỗi phổ biến nhất. Phương thức giống như một hàm, nhưng chạy "trên" một đối tượng. Nếu biến s là một chuỗi, thì mã s.lower() sẽ chạy phương thức lower() trên đối tượng chuỗi đó và trả về kết quả (ý tưởng cơ bản về phương thức chạy trên đối tượng là một trong những ý tưởng cơ bản tạo nên Lập trình hướng đối tượng, OOP). Dưới đây là một số phương thức chuỗi phổ biến nhất:

  • s.lower(), s.upper() – trả về phiên bản chữ thường hoặc chữ hoa của chuỗi
  • s.strip() – trả về một chuỗi không có khoảng trắng ở đầu và cuối
  • s.isalpha()/s.isdigit()/s.isspace()... – kiểm tra xem tất cả các ký tự chuỗi có nằm trong các lớp ký tự khác nhau hay không
  • s.startswith('other'), s.endswith('other') – kiểm tra xem chuỗi bắt đầu hay kết thúc bằng chuỗi khác đã cho
  • s.find('other') – tìm kiếm chuỗi khác đã cho (không phải là biểu thức chính quy) trong s và trả về chỉ mục đầu tiên khi chuỗi bắt đầu hoặc -1 nếu không tìm thấy
  • s.replace('old', 'new') – trả về một chuỗi mà trong đó tất cả các từ 'cũ' được thay thế bằng 'mới'
  • s.Split('delim') – trả về danh sách chuỗi con được phân tách bằng dấu phân cách đã cho. Dấu phân cách không phải là một biểu thức chính quy, nó chỉ là văn bản. 'aaa,bbb,ccc'.split(',') -> ['aaa', 'bbb', 'ccc']. Dưới dạng trường hợp đặc biệt tiện lợi, s.split() (không có đối số) sẽ phân tách trên tất cả các ký tự khoảng trắng.
  • s.join(list) - đối diện với split(), kết hợp các phần tử trong danh sách đã cho với nhau bằng cách sử dụng chuỗi làm dấu phân cách. Ví dụ: '---'.join(['aaa', 'bbb', 'ccc']) -> aaa---bbb---ccc

Khi tìm kiếm "python str" trên Google, bạn sẽ được chuyển đến các phương thức chuỗi python.org chính thức, trong đó liệt kê tất cả các phương thức str.

Python không có loại ký tự riêng biệt. Thay vào đó, một biểu thức như s[8] trả về chuỗi-length-1 chứa ký tự. Với chuỗi-length-1 đó, các toán tử ==, <=, ... tất cả đều hoạt động như mong đợi, vì vậy chủ yếu bạn không cần biết rằng Python không có loại "char" vô hướng riêng biệt.

Lát cắt chuỗi

Cú pháp "Lát cắt" là một cách thuận tiện để tham chiếu đến các phần phụ của trình tự – thường là các chuỗi và danh sách. Lát cắt s[start:end] là các phần tử bắt đầu tại điểm bắt đầu và kéo dài đến nhưng không bao gồm phần kết thúc. Giả sử chúng ta có s = "Xin chào"

chuỗi &#39;hello&#39; với các chỉ mục chữ cái 0 1 2 3 4

  • s[1:4] là 'ell' - các ký tự bắt đầu từ chỉ mục 1 và mở rộng đến nhưng không bao gồm chỉ mục 4
  • s[1:] là 'ello' -- bỏ qua chỉ mục mặc định ở đầu hoặc cuối chuỗi
  • s[:] là 'Hello' -- bỏ qua cả hai luôn cung cấp cho chúng ta một bản sao của toàn bộ nội dung (đây là cách pythonic để sao chép một chuỗi như chuỗi hoặc danh sách)
  • s[1:100] là 'ello' - một chỉ mục quá lớn được cắt bớt xuống độ dài chuỗi

Số chỉ mục tiêu chuẩn dựa trên 0 cho phép dễ dàng truy cập vào các ký tự gần đầu chuỗi. Thay vào đó, Python sử dụng số âm để dễ dàng truy cập các ký tự ở cuối chuỗi: s[-1] là ký tự cuối cùng 'o', s[-2] là 'l' ký tự tiếp theo đến cuối cùng, v.v. Số chỉ mục âm được đếm ngược lại từ cuối chuỗi:

  • s[-1] là 'o' – ký tự cuối cùng (thứ nhất từ cuối)
  • s[-4] là 'e' -- thứ 4 từ cuối
  • s[:-3] là 'Anh ấy' -- đi lên nhưng không bao gồm 3 ký tự cuối cùng.
  • s[-3:] là 'llo' - bắt đầu với ký tự thứ 3 từ cuối và kéo dài đến cuối chuỗi.

Đây là chân lý rõ ràng của các lát cắt đối với mọi chỉ mục n, s[:n] + s[n:] == s. Hàm này có tác dụng ngay cả đối với n giá trị âm hoặc nằm ngoài giới hạn. Hoặc đặt một cách khác s[:n] và s[n:] luôn phân vùng chuỗi thành hai phần chuỗi, bảo toàn tất cả các ký tự. Như chúng ta sẽ thấy trong phần danh sách sau, lát cắt cũng hoạt động với danh sách.

Định dạng chuỗi

Một điều thú vị mà python có thể làm là tự động chuyển đổi các đối tượng thành một chuỗi phù hợp để in. Có 2 cách tích hợp để thực hiện việc này là định dạng chuỗi (còn gọi là "f-strings") và gọi str.format().

Giá trị cố định dạng chuỗi được định dạng

Bạn thường sẽ thấy giá trị cố định dạng chuỗi được định dạng trong các trường hợp như:

  value = 2.791514
  print(f'approximate value = {value:.2f}')  # approximate value = 2.79

  car = {'tires':4, 'doors':2}
  print(f'car = {car}') # car = {'tires': 4, 'doors': 2}

Chuỗi ký tự được định dạng có tiền tố là 'f' (như tiền tố 'r' được sử dụng cho các chuỗi thô). Mọi văn bản nằm ngoài dấu ngoặc nhọn "{}" sẽ được in trực tiếp. Biểu thức trong '{}' được in bằng cách sử dụng thông số kỹ thuật về định dạng được mô tả trong thông số kỹ thuật về định dạng.Bạn có thể thực hiện rất nhiều thao tác gọn gàng với định dạng, bao gồm cắt bớt và chuyển đổi sang ký hiệu khoa học cũng như căn chỉnh trái/phải/giữa.

chuỗi f rất hữu ích khi bạn muốn in ra một bảng gồm các đối tượng và muốn các cột đại diện cho các thuộc tính khác nhau của đối tượng được căn chỉnh như

  address_book = [{'name':'N.X.', 'addr':'15 Jones St', 'bonus': 70},
      {'name':'J.P.', 'addr':'1005 5th St', 'bonus': 400},
      {'name':'A.A.', 'addr':'200001 Bdwy', 'bonus': 5},]

  for person in address_book:
    print(f'{person["name"]:8} || {person["addr"]:20} || {person["bonus"]:>5}')

  # N.X.     || 15 Jones St          ||    70
  # J.P.     || 1005 5th St          ||   400
  # A.A.     || 200001 Bdwy          ||     5

Chuỗi %

Python cũng có một cơ sở cũ hơn giống như printf() để đặt cùng một chuỗi. Toán tử % lấy một chuỗi định dạng kiểu printf ở bên trái (%d int, chuỗi %s, %f/%g dấu phẩy động) và các giá trị phù hợp trong một bộ dữ liệu ở bên phải (một bộ dữ liệu được tạo từ các giá trị được phân tách bằng dấu phẩy, thường được nhóm bên trong dấu ngoặc đơn):

  # % operator
  text = "%d little pigs come out, or I'll %s, and I'll %s, and I'll blow your %s down." % (3, 'huff', 'puff', 'house')

Dòng trên hơi dài -- giả sử bạn muốn chia dòng thành các dòng riêng biệt. Bạn không thể tách dòng sau '%' như trong các ngôn ngữ khác, vì theo mặc định, Python coi mỗi dòng là một câu lệnh riêng (ở bên dấu cộng, đây là lý do chúng ta không cần nhập dấu chấm phẩy trên mỗi dòng). Để khắc phục lỗi này, hãy đưa toàn bộ biểu thức vào trong một cặp dấu ngoặc đơn ngoài – khi đó biểu thức được phép kéo dài nhiều dòng. Kỹ thuật đường chéo mã này hoạt động với các cấu trúc nhóm khác nhau được nêu chi tiết dưới đây: ( ), [ ], { }.

  # Add parentheses to make the long line work:
  text = (
    "%d little pigs come out, or I'll %s, and I'll %s, and I'll blow your %s down."
    % (3, 'huff', 'puff', 'house'))

Như vậy thì tốt hơn, nhưng dòng này vẫn hơi dài. Python cho phép bạn cắt một dòng thành các đoạn rồi tự động nối lại với nhau. Do đó, để rút ngắn dòng này hơn nữa, chúng ta có thể làm như sau:

  # Split the line into chunks, which are concatenated automatically by Python
  text = (
    "%d little pigs come out, "
    "or I'll %s, and I'll %s, "
    "and I'll blow your %s down."
    % (3, 'huff', 'puff', 'house'))

Chuỗi (Unicode so với byte)

Các chuỗi Python thông thường là unicode.

Python cũng hỗ trợ các chuỗi bao gồm các byte thuần tuý (được biểu thị bằng tiền tố 'b' trước một giá trị cố định dạng chuỗi) như:

> byte_string = b'A byte string'
> byte_string
  b'A byte string'

Chuỗi unicode là một loại đối tượng khác với chuỗi byte nhưng các thư viện khác nhau, chẳng hạn như biểu thức chính quy, hoạt động chính xác nếu được chuyển một trong hai loại chuỗi.

Để chuyển đổi một chuỗi Python thông thường thành byte, hãy gọi phương thức mã hoá() trên chuỗi. Đi theo hướng khác, phương thức byte string setter() chuyển đổi các byte thuần tuý được mã hoá thành chuỗi unicode:

> ustring = 'A unicode \u018e string \xf1'
> b = ustring.encode('utf-8')
> b
b'A unicode \xc6\x8e string \xc3\xb1'  ## bytes of utf-8 encoding. Note the b-prefix.
> t = b.decode('utf-8')                ## Convert bytes back to a unicode string
> t == ustring                         ## It's the same as the original, yay!

True

Trong phần đọc tệp, có một ví dụ cho thấy cách mở tệp văn bản bằng một số chuỗi mã hoá và đọc to các chuỗi unicode.

Câu lệnh if

Python không sử dụng { } để bao gồm các khối mã cho if/loops/function, v.v. Thay vào đó, Python sử dụng dấu hai chấm (:) và thụt đầu dòng/khoảng trắng để nhóm các câu lệnh. Kiểm thử boolean cho lệnh if không cần đặt trong ngoặc đơn (sự khác biệt lớn với C++/Java) và có thể có mệnh đề *elif* và *else* (ghi nhớ: từ "elif" có độ dài bằng với từ "else").

Bạn có thể dùng bất kỳ giá trị nào làm kiểm thử if. Tất cả giá trị "0" đều được tính là false: Không có, 0, chuỗi trống, danh sách trống, từ điển trống. Ngoài ra còn có một loại Boolean với hai giá trị: True và False (chuyển đổi thành int, đây là 1 và 0). Python có các phép so sánh thông thường: ==, !=, <, <=, >, >=. Không giống như Java và C, == được nạp chồng để hoạt động chính xác với các chuỗi. Các toán tử boolean là các từ được viết rõ là *and*, *or*, *not* (Python không sử dụng kiểu C &&|!). Đây là ví dụ về mã của một ứng dụng sức khoẻ cung cấp các đề xuất về đồ uống trong suốt cả ngày – hãy lưu ý cách mỗi khối câu lệnh then/else bắt đầu bằng : và các câu lệnh được nhóm theo thụt đầu dòng của chúng:

  if time_hour >= 0 and time_hour <= 24:
    print('Suggesting a drink option...')
    if mood == 'sleepy' and time_hour < 10:
      print('coffee')
    elif mood == 'thirsty' or time_hour < 2:
      print('lemonade')
    else:
      print('water')

Tôi thấy rằng việc bỏ qua ":" là lỗi cú pháp phổ biến nhất của tôi khi nhập loại mã ở trên, có thể vì đó là một điều bổ sung cần nhập so với thói quen C++/Java của tôi. Ngoài ra, đừng đặt kiểm thử boolean trong ngoặc đơn – đó là một thói quen C/Java. Nếu mã ngắn, bạn có thể đặt mã trên cùng một dòng sau ":", như thế này (điều này cũng áp dụng cho các hàm, vòng lặp, v.v.), mặc dù một số người cảm thấy việc tách mọi thứ ra các dòng riêng biệt sẽ dễ đọc hơn.

  if time_hour < 10: print('coffee')
  else: print('water')

Bài tập: string1.py

Để thực hành tài liệu trong phần này, hãy thử bài tập string1.py trong Bài tập cơ bản.