Chuyển đổi văn bản thành Slug (URL)

Chuẩn hóa văn bản thành slug thân thiện với URL, hỗ trợ chuyển thành chữ thường, ký tự phân cách và loại bỏ từ dừng tùy chỉnh.

Tham số và đầu vào

Khuyến nghị sử dụng - hoặc _, độ dài 1~3 ký tự

Kết quả

Tại sao cần Slugify?

🔍 Tối ưu SEO

Từ khóa trong URL giúp công cụ tìm kiếm hiểu nội dung trang, cải thiện thứ hạng. Ví dụ: example.com/blog/how-to-learn-javascript thân thiện hơn example.com/blog/123.

👁️ Tính dễ đọc và chia sẻ

Người dùng có thể biết nội dung chỉ bằng cách nhìn vào URL, rất thân thiện khi chia sẻ trên mạng xã hội và dễ ghi nhớ, nhập thủ công.

💻 Tương thích hệ thống

Tránh lỗi do ký tự đặc biệt trong tên tệp/URL, tương thích đa nền tảng (Windows/Linux/Mac), tránh vấn đề mã hóa.

🗄️ Thân thiện với cơ sở dữ liệu

Dùng làm định danh duy nhất (ví dụ: tên người dùng, thẻ), tránh rủi ro SQL injection, hỗ trợ lập chỉ mục và truy vấn dễ dàng.

Slugify là gì?

Slug là chuỗi văn bản đã được chuẩn hóa để sử dụng làm URL, tên tệp hoặc định danh. Các xử lý phổ biến bao gồm đồng nhất chữ hoa/thường, loại bỏ dấu câu và nối các từ bằng ký tự phân cách.

  • Ưu tiên ASCII: Loại bỏ dấu nhấn và ký hiệu, chỉ giữ lại chữ cái, số và khoảng trắng
  • Tương thích Unicode: Chuẩn hóa NFKD cho hầu hết các ký tự ngôn ngữ trước khi xử lý
  • Thân thiện với URL: Kết quả chỉ chứa chữ cái, số và ký tự phân cách, có thể dùng trực tiếp trong đường dẫn

Các tình huống sử dụng

URL bài viết blog

Làm thế nào để học JavaScript?

how-to-learn-javascript

Đặt tên tệp

Tài liệu yêu cầu sản phẩm v2.0.docx

product-requirements-v2-0.docx

Bộ nhận dạng cơ sở dữ liệu

Người dùng - Trương Tam

user-zhang-san

Câu hỏi thường gặp

Q: Các ký tự Trung Quốc sẽ được xử lý thế nào?

A: Mặc định sẽ loại bỏ dấu thanh điệu và giữ lại các chữ cái pinyin. Các từ thuần Trung Quốc có thể trở thành rỗng; nên chuyển đổi thủ công sang pinyin trước khi slugify, hoặc dùng công cụ chuyển đổi pinyin Trung Quốc.

Q: Tại sao kết quả của tôi lại trống?

A: Có thể đầu vào chỉ gồm dấu câu/biểu tượng/khoảng trắng, hoặc sau khi lọc từ dừng không còn từ nào. Hãy thử tắt tùy chọn từ dừng hoặc điều chỉnh nội dung đầu vào.

Q: Nên dùng - hay _ làm ký tự phân tách?

A: SEO khuyến nghị dùng - (dấu gạch nối), vì Google xem nó như khoảng trắng; _ (gạch dưới) bị xem là ký tự nối, không tốt cho việc tách từ. Đối với tên tệp, có thể chọn tùy ý.

Q: Slug có giới hạn độ dài không?

A: Về mặt kỹ thuật không có giới hạn, nhưng nên giữ dưới 50 ký tự để dễ hiển thị URL và tối ưu SEO. Slug quá dài có thể bị công cụ tìm kiếm cắt ngắn.

Thực hành tốt nhất

Cách làm được khuyến nghị

  • Giữ ngắn gọn (khuyến nghị < 50 ký tự)
  • Tránh ký tự đặc biệt, chỉ dùng chữ cái/số/ký tự phân tách
  • Chuyển thành chữ thường để tránh vấn đề phân biệt chữ hoa/thường
  • Loại bỏ từ dừng để tăng mật độ ngữ nghĩa

Cách nên tránh

  • Đừng bao gồm thông tin nhạy cảm (như ID, email, mật khẩu)
  • Đừng dùng ký tự đặc biệt (như @#$%^&*)
  • Đừng giữ khoảng trắng hoặc ký tự phân tách liên tiếp
  • Đừng lặp lại cùng một từ

Ghi chú kỹ thuật

Chuẩn hóa Unicode:

Sử dụng NFKD để phân tách + loại bỏ ký tự kết hợp (\p{M}), chuyển Café thành Cafe. Hỗ trợ đa số ký tự hệ Latin.

Danh sách từ dừng:

Dựa trên các từ thông dụng trong tiếng Anh (a/an/the/and/or/of/to/in/on/for/at/by/with), có thể mở rộng tùy chỉnh. Cần xử lý riêng cho từ dừng tiếng Trung.

Tương thích trình duyệt:

Cần hỗ trợ ES6+ và biểu thức chính quy Unicode (\p{...}). Các trình duyệt hiện đại (Chrome 64+, Firefox 78+, Safari 11.1+) đều hỗ trợ.

Làm thế nào để tạo Slug bằng ngôn ngữ lập trình?

JavaScript

function slugify(text) {
  return text
    .toLowerCase()
    .normalize("NFKD")
    .replace(/[\u0300-\u036f]/g, "")
    .replace(/[^\w\s-]/g, "")
    .trim()
    .replace(/[\s_-]+/g, "-")
    .replace(/^-+|-+$/g, "");
}

PHP

function slugify($text) {
  $text = mb_strtolower($text);
  $text = iconv("UTF-8", "ASCII//TRANSLIT", $text);
  $text = preg_replace("/[^\w\s-]/", "", $text);
  $text = preg_replace("/[\s_-]+/", "-", $text);
  return trim($text, "-");
}

Python

import re
import unicodedata

def slugify(text):
    text = text.lower()
    text = unicodedata.normalize("NFKD", text)
    text = text.encode("ascii", "ignore").decode("ascii")
    text = re.sub(r"[^\w\s-]", "", text)
    text = re.sub(r"[\s_-]+", "-", text)
    return text.strip("-")

Go

import (
    "regexp"
    "strings"
    "golang.org/x/text/unicode/norm"
)

func Slugify(text string) string {
    text = strings.ToLower(text)
    text = norm.NFKD.String(text)
    re := regexp.MustCompile(`[^\w\s-]`)
    text = re.ReplaceAllString(text, "")
    re = regexp.MustCompile(`[\s_-]+`)
    text = re.ReplaceAllString(text, "-")
    return strings.Trim(text, "-")
}

Ruby

require "unicode"

def slugify(text)
  text = text.downcase
  text = Unicode.nfkd(text).gsub(/[^\x00-\x7F]/, "")
  text = text.gsub(/[^\w\s-]/, "")
  text = text.gsub(/[\s_-]+/, "-")
  text.strip.gsub(/^-+|-+$/, "")
end

Java

import java.text.Normalizer;

public static String slugify(String text) {
    text = text.toLowerCase();
    text = Normalizer.normalize(text, Normalizer.Form.NFKD);
    text = text.replaceAll("[^\\w\\s-]", "");
    text = text.replaceAll("[\\s_-]+", "-");
    return text.replaceAll("^-+|-+$", "");
}