So sánh 2 chuỗi trong python
Python được tạo ra bởi Guido van Rossum vào đầu những năm 90s. Ngày nay nó là một trong những ngôn ngữ phổ biến nhất còn tồn tại. Tôi thích Python vì sự rõ ràng, trong sáng về mặt cú pháp. Về cơ bản, Python có thể coi như một loại mã giả (pseudocode) có thể thực thi được. Show Mọi phản hồi đều sẽ được tích cực ghi nhận! Bạn có thể liên lạc với tôi qua Twitter @louiedinh hoặc louiedinh [at] [google’s email service] Lưu ý: Bài viết này áp dụng riêng cho Python 3. Truy cập vào đây nếu bạn muốn học phiên bản cũ Python 2.7 Dòng bình luận (comment) bắt đầu bằng dấu thăng (#)""" Những chuỗi ký tự (string) nằm trên nhiều dòng """
####################################################1. Các kiểu dữ liệu cơ bản và Các phép toán#################################################### Bạn có những con số3 # => 3 Tính toán với những con số là những điều có thể bạn sẽ làm1 + 1 # => 2 8 - 1 # => 7 10 * 2 # => 20 35 / 5 # => 7.0 Kết quả của phép chia số nguyên sẽ được làm tròn xuống cho cả số dương và số âm5 // 3 # => 1 5.0 // 3.0 # => 1.0 # phép chia số nguyên cũng áp dụng được cho kiểu dữ liệu float biểu diễn số thực -5 // 3 # => -2 -5.0 // 3.0 # => -2.0 Kết quả của phép chia luôn là số thực10.0 / 3 # => 3.3333333333333335 Phép toán lấy phần dư (modulo)7 % 3 # => 1 Phép lũy thừa (x**y, x lũy thừa y)2**3 # => 8 Áp đặt thứ tự tính toán bằng dấu ngoặc(1 + 3) * 2 # => 8 Kiểu Boolean cũng là một kiểu dữ liệu cơ bản (Lưu ý: ký tự đầu tiên viết hoa)True False Phủ định bằng từ khóa 'not'not True # => False not False # => True Các phép toán với kiểu BooleanLưu ý từ khóa "and" và "or" là case-sensitiveTrue and False # => False False or True # => True Lưu ý khi sử dụng các phép toán của kiểu Boolean với số nguyên 'int'False là 0 và True là 1Đừng nhầm lẫn các phép toán Boolean cho số nguyên và các phép toán and/or trên bit (& và |)0 and 2 # => 0 -5 or 0 # => -5 0 == False # => True 2 == True # => False 1 == True # => True -5 != False != True #=> True So sánh bằng với ==1 == 1 # => True 2 == 1 # => False So sánh không bằng với !=1 != 1 # => False 2 != 1 # => True Các phép so sánh khác1 < 10 # => True 1 > 10 # => False 2 <= 2 # => True 2 >= 2 # => True Các phép so sánh có thể xâu chuỗi với nhau!1 < 2 < 3 # => True 2 < 3 < 2 # => False (is vs. ==) từ khóa is kiểm tra xem 2 biến có cùng tham chiếu một đối tượng, còn == kiếm traxem hai đối tượng có cùng giá trị hay không.a = [1, 2, 3, 4] # a trỏ tới một danh sách (list) mới, [1, 2, 3, 4] b = a # b trỏ tới nơi mà a cũng đang trỏ tới b is a # => True, a và b cùng trỏ tới một đối tượng b == a # => True, đối tượng mà a và b trỏ tới có cùng giá trị b = [1, 2, 3, 4] # b trỏ tới một danh sách mới, [1, 2, 3, 4] b is a # => False, a và b không cùng trỏ tới một đối tượng b == a # => True, đối tượng mà a và b trỏ tới không có cùng giá trị Chuỗi ký tự được tạo ra bằng dấu nháy kép " hoặc nháy đơn '"Đây là một chuỗi ký tự." 'Đây cũng là một chuỗi ký tự.' Chuỗi ký tự có thể được cộng với nhau can be added too! Tuy nhiên nên tránh làm như vậy"Xin " + "chào!" # => "Xin chào!" Các chuỗi ký tự không phải là biến (literals) có thể được nối với nhau mà không cần dùng phép cộng '+'"Xin " "chào!" # => "Xin chào!" Một chuỗi ký tự có thể xem như một danh sách (list) các ký tự"Đây là một chuỗi ký tự"[0] # => 'Đ' Bạn có thể tìm chiều dài một chuỗilen("Đây là một chuỗi") # => 16 .format có thể được dùng để định dạng chuỗi, ví dụ như:"{} có thể được {}".format("Chuỗi ký tự", "định dạng") # => "Chuỗi ký tự có thể được định dạng" Bạn có thể lặp lại đối số (arguments) khi định dạnh để không phải gõ nhiều lần"{0} be nimble, {0} be quick, {0} jump over the {1}".format("Jack", "candle stick") => "Jack be nimble, Jack be quick, Jack jump over the candle stick"Bạn có thể dùng từ khóa nếu bạn không muốn đếm"{name} wants to eat {food}".format(name="Bob", food="lasagna") # => "Bob wants to eat lasagna" Nếu code Python 3 của bạn cần phải chạy với Python 2.5 hoặc các bản cũ hơn, bạn cũng có thểdùng cách định dạng cũ:"%s can be %s the %s way" % ("Strings", "interpolated", "old") # => "Strings can be interpolated the old way" None là một đối tượngNone # => None Đừng dùng so sánh bằng "==" để so sánh đối tượng với NoneThay vào đó dùng is. Nó sẽ kiểm tra xem một đối tượng có đồng nhất với None hay không."etc" is None # => False None is None # => True None, 0, và chuỗi/danh sách (list)/từ điển (dict)/tuple rỗng khi chuyển về kiểu Boolean đều có giá trị là False.Tất cả những giá trị khác đều là Truebool(0) # => False bool("") # => False bool([]) # => False bool({}) # => False bool(()) # => False #################################################### 2. Biến và Các kiểu dữ liệu gộp (Collections)#################################################### Hàm print trong Pythonprint("Tôi là Python. Rất hân hạnh được làm quen!") # => Tôi là Python. Rất hân hạnh được làm quen! Hàm print mặc định in thêm ký tự xuống dòngDùng đối số tùy chọn (optional argument) để thay đổi cách kết thúc chuỗi.print("Hello, World", end="!") # => Hello, World! Một cách đơn giản để lấy dữ liệu vào từ bàn phíminput_string_var = input("Nhập dữ liệu: ") # Trả về dữ liệu vào là một chuỗi Lưu ý: Trong những phiên bản cũ của Python input() có tên là raw_input()Không cần phải khai báo biến mà chỉ có gán giá trị cho biến.Quy ước là sử dụng chữ_viết_thường_có_dấu_gạch_dướisome_var = 5 some_var # => 5 Truy cập một biến chưa được gán trước đó sẽ tạo ra biệt lệ (exception).Đọc mục Luồng điều khiển để hiểu thêm về việc giải quyết các biệt lệ (exception handling)some_unknown_var # Sinh ra một biệt lệ kiểu NameError if có thể dùng như một biểu thứcTương đương với phép toán ba ngôi trong C: '?:'"yahoo!" if 3 > 2 else 2 # => "yahoo!" Kiểu danh sách (list) lưu trữ chuỗi đối tượng tuần tựli = [] Bạn có thể bắt đầu với một danh sách đã có sãn các phần tửother_li = [4, 5, 6] Thêm phần tử vào cuối danh sách bằng phương thức appendli.append(1) # li bây giờ là [1] li.append(2) # li bây giờ là [1, 2] li.append(4) # li bây giờ là [1, 2, 4] li.append(3) # li bây giờ là [1, 2, 4, 3] Xóa phần tử cuối cùng bằng phương thức popli.pop() # => 3 and li is now [1, 2, 4] Sau đó ta có thể đưa đối tượng trở lại danh sáchli.append(3) # li trở lại là [1, 2, 4, 3]. Truy cập một danh sách như bạn làm với một mảng (array)li[0] # => 1 Truy cập phần tử cuối cùngli[-1] # => 3 Truy cập ngoài giới hạn sẽ tạo ra biệt lệ IndexErrorli[4] # Sinh ra một biệt lệ kiểu IndexError Bạn có thể truy cập một đoạn bằng phép cắt (slice).Chỉ mục bắt đầu được tính làm điểm bắt đầu còn chỉ mục kết thúc thì không, mà là chỉ mục của phần tử tiếp theo phần tử kết thúc(Về mặt toán học thì đây là một đoạn đóng/mở, hay nửa đoạn)li[1:3] # => [2, 4] Lấy từ vị trí thứ 3 đến hếtli[2:] # => [4, 3] Lấy từ đầu đến vị trí thứ 3li[:3] # => [1, 2, 4] Lấy những phần tử có chỉ mục chẵnli[::2] # =>[1, 4] Trả về bản sao của danh sách bị đảo ngượcli[::-1] # => [3, 4, 2, 1] Kết hợp 3 tham số để làm những phép cắt phức tạp hơnli[start:end:step]Tạo ra một bản sao sâu (deep copy) bằng phép cắtli2 = li[:] # => li2 = [1, 2, 4, 3] but (li2 is li) will result in false. Xóa phần tử nào đó của danh sách bằng "del"del li[2] # li is now [1, 2, 3] Xóa đi phần tử đầu tiên mang một giá trị nhất địnhli.remove(2) # li bây giờ là [1, 3] li.remove(2) # Sinh ra biệt lệ kiểu ValueError vì 2 không tồn tại trong danh sách Chèn một phần tử vào một vị trí cụ thểli.insert(1, 2) # li bây giờ lại là [1, 2, 3] Tìm chỉ mục của của phần tử đầu tiên mang một giá trị nhất địnhli.index(2) # => 1 li.index(4) # Sinh ra biệt lệ a ValueError as 4 is not in the list Bạn có thể cộng dồn các danh sáchLưu ý: giá trị của li và other_li không đổili + other_li # => [1, 2, 3, 4, 5, 6] Nối danh sách bằng "extend()"li.extend(other_li) # Now li is [1, 2, 3, 4, 5, 6] Kiểm tra sự tồn tại của một phần tử trong danh sách bằng "in"1 in li # => True Xác định độ dài bằng "len()"len(li) # => 6 Tuple cũng giống như danh sách nhưng không thể thay đổi giá trị được (immutable)tup = (1, 2, 3) tup[0] # => 1 tup[0] = 3 # Sinh ra biệt lệ kiểu TypeError Lưu ý rằng tuple có độ dài là 1 phải có dấu phẩy theo sau phần tử cuốinhưng tuples có độ dài khác, ngay cả tuple rỗng, thì không cần như vậytype((1)) # => Hầu hết các phép toán của danh sách đều áp dụng được cho tupleslen(tup) # => 3 tup + (4, 5, 6) # => (1, 2, 3, 4, 5, 6) tup[:2] # => (1, 2) 2 in tup # => True Bạn có thể gán giá trị cho nhiều biến một lúc bằng tuple (tuple unpacking)a, b, c = (1, 2, 3) # a is now 1, b is now 2 and c is now 3 Sau đây là unpacking kiểu mở rộnga, *b, c = (1, 2, 3, 4) # a bây giờ là 1, b là [2, 3] và c là 4 Tuple được tự động tạo ra nếu bạn không để dấu ngoặc đơnd, e, f = 4, 5, 6 Hoán đổi hai biến trở nên dễ dànge, d = d, e # d bây giờ là 5 và e là 4 Kiểu dữ liệu từ điển (dictionaries) lưu trữ ánh xạ từ các khóa (keys) đến các giá trị (values)empty_dict = {} Sau đây là một từ điển có sẵn phần tửfilled_dict = {"one": 1, "two": 2, "three": 3} Lưu ý rằng khóa của từ điển phải có kiểu dữ liệu thuộc loại immutable. Điều này để bảo đảm rằngkhóa đó luôn được chuyển hóa thành một giá trị băm (hash value) duy nhất khi tìm kiếm trong từ điểnNhững kiểu immutable bao gồm số nguyên (int), số thực (float), chuỗi ký tự (string), hay tupleinvalid_dict = {[1,2,3]: "123"} # => Sinh ra biệt lệ kiểu TypeError: unhashable type: 'list' valid_dict = {(1,2,3):[1,2,3]} # Tuy nhiên, giá trị có thể thuộc bất kỳ kiểu gì Truy cập giá trị của một từ khóa bằng dấu []filled_dict["one"] # => 1 Tất cả khóa trong một từ điển có thể được chuyển thành một đối tượng khả lặp (iterable).Chúng ta cần phải gọi hàm list() để chuyển một iterable thành một danh sách.Chúng ta sẽ bàn về vấn đề này sau. Lưu ý - Thứ tự của khóa trong từ điển sẽ không được đảm bảo.Những gì bạn thấy khi chạy dòng code dưới đây có thể sẽ không hoàn toàn giống như vậy.list(filled_dict.keys()) # => ["three", "two", "one"] Tất cả các giá trị có thể chuyển thành một đối tượng khả lặp bằng cách gọi hàm "values()".Chúng ta cũng vẫn phải gọi hàm list() nếu muốn chuyển nó thành một danh sách. Lưu ý - thứtự của giá trị cũng không được đảm bảolist(filled_dict.values()) # => [3, 2, 1] Sự tồn tại của khóa trong từ điển có thể kiểm tra được thông qua từ khóa "in""one" in filled_dict # => True 1 in filled_dict # => False Truy xuất giá trị của một khóa không tồn tại trong từ điển sẽ tạo ra biệt lệ KeyErrorfilled_dict["four"] # KeyError Dừng phương thức "get()" để tránh tạo ra biệt lệ KeyErrorfilled_dict.get("one") # => 1 filled_dict.get("four") # => None Phương thức get hỗ trợ một đối số mặt định khi không thể tìm thấy giá trị ứng với từ khóafilled_dict.get("one", 4) # => 1 filled_dict.get("four", 4) # => 4 "setdefault()" chèn một giá trị ứng với khóa nếu khóa đó không có sẵn trong từ điểnfilled_dict.setdefault("five", 5) # filled_dict["five"] is set to 5 filled_dict.setdefault("five", 6) # filled_dict["five"] is still 5 Thêm khóa và giá trị vào từ điểnfilled_dict.update({"four":4}) # => {"one": 1, "two": 2, "three": 3, "four": 4} filled_dict["four"] = 4 # another way to add to dict Xóa một khóa ra khỏi từ điển bằng từ khóa deldel filled_dict["one"] # Removes the key "one" from filled dict Bắt đầu từ Python 3.5 bạn có thể unpack từ điển trong một từ điển khác{'a': 1, {'b': 2}} # => {'a': 1, 'b': 2} {'a': 1, {'a': 2}} # => {'a': 2} Kiểu tập hợp (set) lưu trữ ... tập hợpempty_set = set() Khởi tạo giá trị một tập hợp với nhiều giá tri. Vâng, nhìn nó khá giống từ điển.some_set = {1, 1, 2, 2, 3, 4} # some_set is now {1, 2, 3, 4} Tương tự như khóa của từ điển, phần tử của một tập hợp cũng phải là immutableinvalid_set = {[1], 1} # => Sinh ra biệt lệ TypeError: unhashable type: 'list' valid_set = {(1,), 1} Thêm một phần tử vào tập hợpfilled_set.add(5) # filled_set is now {1, 2, 3, 4, 5} Thực hiện phép giao hai tập hợp bằng phép toán &other_set = {3, 4, 5, 6} filled_set & other_set # => {3, 4, 5} Thực hiện phép hợp bằng phép toán |filled_set | other_set # => {1, 2, 3, 4, 5, 6} Lấy hiệu của hai tập hơp bằng phép toán -{1, 2, 3, 4} - {2, 3, 5} # => {1, 4} Lấy hiệu đối xứng bằng phép toán ^{1, 2, 3, 4} ^ {2, 3, 5} # => {1, 4, 5} Kiểm tra tập hợp bên trái là tập cha của bên phải{1, 2} >= {1, 2, 3} # => False Kiểm tra xem tập hợp bên trái có phải là tập con của tập hợp bên phải{1, 2} <= {1, 2, 3} # => True Kiểm tra sự tồn tại của một phần tử trong tập hợp bằng từ khóa in2 in filled_set # => True 10 in filled_set # => False #################################################### 3. Luồng điều khiển và kiểu khả lặp#################################################### Đầu tiên hãy tạo ra một biếnsome_var = 5 Sau đây là một câu lệnh if. Khoảng cách lề rất quan trọng trong PythonQuy ước chung là dùng khoảng trắng chứ không phải ký tự tabChuỗi sau sẽ được in ra "some_var is smaller than 10"if some_var > 10: elif some_var < 10: # Phần elif là tùy chọn. else: # else cũng là tùy chọn. """
Lặp qua một danh sách bằng for
in ra: """
for animal in ["dog", "cat", "mouse"]: """
"range(number)" trả về một đối tượng khả lặp kiểu số
từ 0 đến giá trị của number
in ra: """
for i in range(4): """
"range(lower, upper)" trả về một đối tượng khả lặp kiểu số
từ giá trị lower đến giá trị upper
in ra: """
for i in range(4, 8): """
"range(lower, upper, step)" trả về một đối tượng khả lặp kiểu số
từ giá trị lower đến giá trị upper, tăng dần theo giá trị
của step. Nếu không có giá trị của step thì mặc định là 1.
in ra: """
for i in range(4, 8, 2): """
Vòng lặp while tiếp tục lặp khi điều kiện còn được thỏa mãn
in ra: """
x = 0
while x < 4: # Handle exceptions with a try/except blockĐối phó với biệt lệ bằng khối lệnh try/excepttry: except IndexError as e: except (TypeError, NameError): else: # Không bắt buộc phải sử dụng else nhưng nếu dùng thì nó phải sau tất cả các khối except finally: # Luôn thực thi trong mọi hoàn cảnh # Thay vì dùng try/finally để thu hồi tài nguyên (resources) ta có thể dùng with
with open("myfile.txt") as f: # Python hỗ trợ kiểu dữ liệu khả lặp (iterable).Một đối tượng khả lặp có thể được xem như là một chuỗi các đối tượng tuần tự (sequence)Đối tượng trả về bởi hàm range là một khả lặp.filled_dict = {"one": 1, "two": 2, "three": 3} our_iterable = filled_dict.keys() print(our_iterable) # => dict_keys(['one', 'two', 'three']). Đây là một đối tượng khả lặp Ta có thể lặp qua đối tượngfor i in our_iterable: # Tuy nhiên chúng ta không thể truy cập phần tử bằng chỉ mục
our_iterable[1] # Sinh ra biệt lệ TypeErrorMột đối tượng khả lặp là đối tượng có thể tạo ra một iteratorour_iterator = iter(our_iterable) iterator là một đối tượng ghi nhớ được trạng thái trong quá trình nó được duyệt quađối tượng kế tiếp có thể truy cập được bằng hàm nextnext(our_iterator) # => "one" Nó ghi nhớ trạng thái trong quá trình lặpnext(our_iterator) # => "two" next(our_iterator) # => "three" Sau khi iterator đã trả về tất cả dữ liệu, nó sẽ sinh ra biệt lệ kiểu StopIterationnext(our_iterator) # Sinh ra biệt lệ StopIteration Ta có thể lấy tất cả phần tử của một iterator bằng cách gọi hàm list với nólist(filled_dict.keys()) # => Returns ["one", "two", "three"] #################################################### 4. Hàm#################################################### Dùng từ khóa def để định nghĩa hàmdef add(x, y): # Gọi một hàm với đối số
add(5, 6) # => In ra "x is 5 and y is 6" và trả về 11Một cách khác để gọi hàm là dùng đối số có từ khóa (keyword arguments)add(y=6, x=5) # Đối số có từ khóa có thể xuất hiện với thứ tự bất kỳ Bạn có thể định nghĩa hàm có số lượng đối số vị trí (positional arguments) không biết trướcdef varargs(*args): varargs(1, 2, 3) # => (1, 2, 3)Số lượng tham số từ khóa cũng có thể không cần biết trướcdef keyword_args(**kwargs): # Thử gọi hàm để xem điều gì xảy ra
keyword_args(big="foot", loch="ness") # => {"big": "foot", "loch": "ness"}Có thể định nghĩa hàm dùng cả hai loại đối sốdef all_the_args(*args, **kwargs): """
all_the_args(1, 2, a=3, b=4) in ra: """Khi gọi hàm, bạn có thể làm ngược với khi định nghĩaDùng dấu để lấy giá trị từ args và * với giá trị từ kwargsargs = (1, 2, 3, 4) kwargs = {"a": 3, "b": 4} all_the_args(*args) # tương đương với foo(1, 2, 3, 4) all_the_args(**kwargs) # tương đương với foo(a=3, b=4) all_the_args(*args, **kwargs) # tương đương với foo(1, 2, 3, 4, a=3, b=4) Trả về nhiều giá trị (gán vào một tuple)def swap(x, y): x = 1
y = 2
x, y = swap(x, y) # => x = 2, y = 1(x, y) = swap(x,y) # dấu ngoặc đơn đã được bỏ đi những vẫn có thể được thêm vàoTầm vực của hàmx = 5 def set_x(num): def set_global_x(num): set_x(43)
set_global_x(6)Hàm trong Python cũng là đối tượngdef create_adder(x): add_10 = create_adder(10)
add_10(3) # => 13Có những hàm không tên(lambda x: x > 2)(3) # => True (lambda x, y: x 2 + y 2)(2, 1) # => 5 Có những hàm cấp cao được hỗ trọ sẵnlist(map(add_10, [1, 2, 3])) # => [11, 12, 13] list(map(max, [1, 2, 3], [4, 2, 1])) # => [4, 2, 3] list(filter(lambda x: x > 5, [3, 4, 5, 6, 7])) # => [6, 7] list comprehension có thể dùng để hay thế map và filterlist comprehension lưu giá trị xuất vào một danh sách mà bản thân nó có thể lồng trong danh sách khác[add_10(i) for i in [1, 2, 3]] # => [11, 12, 13] [x for x in [3, 4, 5, 6, 7] if x > 5] # => [6, 7] Tập hơp và từ điển cũng có thể được tao ra thông qua set comprehension và dict comprehension{x for x in 'abcddeef' if x not in 'abc'} # => {'d', 'e', 'f'} {x: x**2 for x in range(5)} # => {0: 0, 1: 1, 2: 4, 3: 9, 4: 16} #################################################### 5. Mô đun#################################################### Bạn có thể import một mô đunimport math print(math.sqrt(16)) # => 4.0 Bạn có thể lấy một hàm cụ thể từ một mô đunfrom math import ceil, floor print(ceil(3.7)) # => 4.0 print(floor(3.7)) # => 3.0 Hoặc import tất cả hàm từ một mô đunCảnh báo: đây không phải là một cách hayfrom math import * Có thể làm tên của module ngắn lạiimport math as m math.sqrt(16) == m.sqrt(16) # => True Mô đun trong Python chỉ là những tập tin Python bình thường. Bạncó thể viết mô đun của mình và import chúng. Tên của mô đuncũng là tên của tập tin.You can find out which functions and attributesare defined in a module.Bạn có thể liệt kê những hàm và thuộc tínhđược định nghĩa trong một mô đunimport math dir(math) Nếu bạn có một tập tin code Python gọi là math.py ở cùngthư mục với tập tin hiện tai, tập tin math.py sẽđược nạp vào thay vì mô đun được cung cấp sẵn (built-in) trong Python.Điều này xảy ra vì thư mục hiện tại có ưu tiênhơn những thư viện cung cấp sẵn.#################################################### 6. Lớp (classes)#################################################### Ta dùng từ khóa "class" đề định nghĩa một lớpclass Human: # Khi trình thông dịch Python đọc một tập tin mã nguồn, nó thực thi tất cả code trong đó.Kiểm tra giá trị của name bảo đảm rằng đoạn mã bên dưới chỉ thực thi khimô đun này là chương trình chínhif name == 'main': ####################################################6.1 Đa thừa kế#################################################### Một định nghĩa lớp khácclass Bat: if name == 'main': # Để tận dụng việc mô đun hóa thành từng tập tin, bạn có thể đặt những lớp định nghĩa ở trên vào các tập tin riêng,ví dụ như human.py và bat.pyĐể import hàm từ tập tin khác dừng cấu trúc saufrom "filename-without-extension" import "function-or-class"superhero.pyfrom human import Human from bat import Bat Batman thừa kế từ lớp Human và Batclass Batman(Human, Bat): if name == 'main': ####################################################7. Phần nâng cao#################################################### Generator giúp ta viết những đoạn code lười biếng (áp dụng nguyên tắc lazy evaluation)def double_numbers(iterable): # Generators tiết kiệm bộ nhớ vì nó chỉ tải dữ liệu khi cầnxử lý giá trị kế tiếp của một đối tượng khả lặp. Điều này cho phép generator thực hiệnnhững thao tác mà bình thường không làm được trên những khoảng giá trị lớnLưu ý: |