Regex cụ thể cho các ký tự có dấu (Diacritics)


166

Tôi đã xem Stack Overflow ( thay thế các ký tự .. eh , làm thế nào JavaScript không tuân theo tiêu chuẩn Unicode liên quan đến RegExp , v.v.) và thực sự không tìm thấy câu trả lời cụ thể cho câu hỏi:

How can JavaScript match for accented characters (those with diacritical marks)?

Tôi đang buộc một trường trong giao diện người dùng phải khớp với định dạng: last_name, first_name (lần cuối [dấu phẩy] trước tiên) và tôi muốn cung cấp hỗ trợ cho dấu phụ, nhưng rõ ràng trong JavaScript khó hơn một chút so với các ngôn ngữ / nền tảng khác.

Đây là phiên bản gốc của tôi, cho đến khi tôi muốn thêm hỗ trợ dấu phụ:

/^[a-zA-Z]+,\s[a-zA-Z]+$/

Hiện tại tôi đang tranh luận một trong ba phương pháp để thêm hỗ trợ, tất cả những phương pháp tôi đã thử nghiệm và hoạt động (ít nhất là ở một mức độ nào đó, tôi không thực sự biết "mức độ" của phương pháp thứ hai là gì). Họ đây rồi:

Liệt kê rõ ràng tất cả các ký tự có dấu mà tôi muốn chấp nhận là hợp lệ (khập khiễng và quá phức tạp):


var accentedCharacters = "àèìòùÀÈÌÒÙáéíóúýÁÉÍÓÚÝâêîôûÂÊÎÔÛãñõÃÑÕäëïöüÿÄËÏÖÜŸçÇßØøÅåÆæœ";
// Build the full regex
var regex = "^[a-zA-Z" + accentedCharacters + "]+,\\s[a-zA-Z" + accentedCharacters + "]+$";
// Create a RegExp from the string version
regexCompiled = new RegExp(regex);
// regexCompiled = /^[a-zA-ZàèìòùÀÈÌÒÙáéíóúýÁÉÍÓÚÝâêîôûÂÊÎÔÛãñõÃÑÕäëïöüÿÄËÏÖÜŸçÇßØøÅåÆæœ]+,\s[a-zA-ZàèìòùÀÈÌÒÙáéíóúýÁÉÍÓÚÝâêîôûÂÊÎÔÛãñõÃÑÕäëïöüÿÄËÏÖÜŸçÇßØøÅåÆæœ]+$/
  • Điều này khớp chính xác tên / họ với bất kỳ ký tự có dấu nào được hỗ trợ trong accentedCharacters.

Cách tiếp cận khác của tôi là sử dụng .lớp nhân vật, để có một biểu thức đơn giản hơn:

var regex = /^.+,\s.+$/;
  • Điều này sẽ phù hợp với bất cứ điều gì, ít nhất là ở dạng : something, something. Điều đó ổn thôi, tôi cho rằng ...

Cách tiếp cận cuối cùng, mà tôi vừa tìm thấy có thể đơn giản hơn ...

/^[a-zA-Z\u00C0-\u017F]+,\s[a-zA-Z\u00C0-\u017F]+$/
  • Nó phù hợp với một loạt các ký tự unicode - được thử nghiệm và hoạt động, mặc dù tôi không thử bất cứ điều gì điên rồ, chỉ là những thứ bình thường tôi thấy trong khoa ngôn ngữ của chúng tôi cho các tên giảng viên.

Đây là mối quan tâm của tôi:

  1. Giải pháp đầu tiên là quá hạn chế, và cẩu thả và hỗn độn ở đó. Nó sẽ cần phải được thay đổi nếu tôi quên một hoặc hai nhân vật, và điều đó không thực tế lắm.
  2. Giải pháp thứ hai là tốt hơn, súc tích, nhưng có lẽ nó phù hợp hơn nhiều so với thực tế. Tôi không thể tìm thấy bất kỳ tài liệu thực tế nào về chính xác những gì .khớp, chỉ là khái quát của "bất kỳ ký tự nào ngoại trừ ký tự dòng mới" (từ một bảng trên MDN ).
  3. Giải pháp thứ ba có vẻ là chính xác nhất, nhưng có bất kỳ vấn đề nào không? Tôi không quen thuộc lắm với Unicode, ít nhất là trong thực tế, nhưng nhìn vào bảng mã / tiếp tục của bảng đó , \u00C0-\u017Fdường như khá chắc chắn, ít nhất là cho đầu vào dự kiến ​​của tôi.

    • Khoa sẽ không gửi biểu mẫu với tên của họ bằng ngôn ngữ mẹ đẻ của họ (ví dụ: tiếng Ả Rập, tiếng Trung Quốc, tiếng Nhật, v.v.) vì vậy tôi không phải lo lắng về các ký tự ngoài tiếng Latin

Vì vậy, câu hỏi thực sự : Cách tiếp cận nào trong ba cách này phù hợp nhất cho nhiệm vụ? Hoặc có giải pháp tốt hơn?


1
Dường như không có lý do cụ thể để sử dụng các biểu thức phức tạp hơn. Điều duy nhất về giải pháp đơn giản nhất là, nó cũng sẽ phù hợp với "cái gì đó, cái gì đó, cái gì đó". Bạn có thể sử dụng một cái gì đó như regex = /^[^,]+,\s[^,]+$/;để ngăn chặn điều đó.
usr2564301

4
Nhìn thoáng qua, cái đầu tiên sẽ không khớp với tên chung "O'Donnell, Chris" cũng không ghép tên cuối cùng với dấu gạch nối, cũng không có nhiều tên cuối (v.v.). Xem các lập trình viên sai lầm tin vào tên cho mọi cạm bẫy có thể.
usr2564301

" Các .nguyên tử phù hợp với bất cứ điều gì ngoại trừ dòng mới " thực sự là khá chính xác :-)
Bergi

1
Nếu bạn có thể sử dụng một thư viện bổ sung, bạn có thể xem câu trả lời của tôi ở đây
stema 19/12/13

Jongware, tôi thực sự chỉ đọc bài báo đó trong khi tôi đang duyệt SO để tìm câu trả lời cho câu hỏi của mình - Tôi cũng hoàn toàn quên mất dấu gạch ngang và dấu nháy đơn và tương tự, tôi quan tâm hơn đến việc đưa nó ra quốc tế trước: P Tôi rất vui vì bạn đã mang nó mặc dù lên! Và Stema, tôi thực sự đã xem thư viện đó và tôi tránh kết hợp các thư viện vì đây là tất cả trên Google Apps Script - kết hợp các thư viện bên ngoài sẽ là một cơn ác mộng và tôi sẽ chỉ sử dụng nó (trong trường hợp này) cho một lĩnh vực cụ thể ... loại quá mức cần thiết: P
Chris Cirefice 19/12/13

Câu trả lời:


274

Cách dễ dàng hơn để chấp nhận tất cả các dấu là:

[A-zÀ-ú] // accepts lowercase and uppercase characters
[A-zÀ-ÿ] // as above but including letters with an umlaut (includes [ ] ^ \ × ÷)
[A-Za-zÀ-ÿ] // as above but not including [ ] ^ \
[A-Za-zÀ-ÖØ-öø-ÿ] // as above but not including [ ] ^ \ × ÷

Xem https://unicode-table.com/en/ để biết các ký tự được liệt kê theo thứ tự số.


2
Nó hoạt động độc đáo, +1, nhưng bạn có thể giải thích tại sao nó hoạt động không?
Pierre Henry

1
@PierreHenry -định nghĩa một phạm vi và kỹ thuật này khai thác thứ tự các ký tự trong bộ ký tự để xác định một phạm vi liên tục, tạo ra một giải pháp siêu súc tích cho vấn đề
Angad

8
trận đấu này sẽ không nhấn mạnh (và các ký tự không phải từ khác giữa Za)?
jcuenod

21
Điều này phù hợp với ít nhất các ký tự [,], ^ và \, không bao gồm các ký tự.
Nate

2
Không hoạt động, một vài ký tự trong phạm vi này không phải là ký tự có dấu (ví dụ U + 00D7 là dấu nhân) xem điều này: unicode-table.com/en
Jérémy Pouyet

39

Phạm vi Latin có dấu \u00C0-\u017Fkhông đủ cho cơ sở dữ liệu tên của tôi, vì vậy tôi đã mở rộng regex thành

[a-zA-Z\u00C0-\u024F]
[a-zA-Z\u00C0-\u024F\u1E00-\u1EFF] // includes even more Latin chars

Tôi đã thêm các khối mã này ( \u00C0-\u024Fbao gồm ba khối liền kề cùng một lúc):

Lưu ý rằng \u00C0-\u00FFthực sự chỉ là một phần của Bổ sung Latin-1 . Phạm vi đó bỏ qua các tín hiệu điều khiển không thể in được và tất cả các biểu tượng ngoại trừ bội số được đặt lúng túng × \u00D7và chia \u00F7.

[a-zA-Z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u024F] // exclude ×÷

Nếu bạn cần nhiều điểm mã hơn, bạn có thể tìm thấy nhiều phạm vi hơn trong Danh sách các ký tự Unicode của Wikipedia . Ví dụ: bạn cũng có thể thêm Latin Extended-C , DE , nhưng tôi đã loại bỏ chúng vì hiện tại chỉ có các nhà sử học quan tâm đến chúng và bộ D và E thậm chí không hiển thị chính xác trong trình duyệt của tôi.

Regex ban đầu dừng lại ở \u017Fborked trên tên "Șenol". Theo Phân tích Unicode của FontSpace , ký tự đầu tiên đó là \u0218, LATIN VỐN THƯỞNG VỚI COMMA DƯỚI ĐÂY. (Vâng, nó thường được đánh vần bằng chữ cedilla-S \u015E, "Şenol." Nhưng tôi không bay sang Thổ Nhĩ Kỳ để nói với anh ta, "Bạn đang đánh vần sai tên của bạn!")


1
Có một cái nhìn về khối Latin bảng unicode , tôi nghĩ bạn cũng nên bao gồm \ u1e00- \ u1eff, vì vậy tôi đang làm[a-zA-Z\u00c0-\u024f\u1e00-\u1eff]
cprcrack

18

Phương pháp nào trong ba cách tiếp cận này phù hợp nhất cho nhiệm vụ?

Phụ thuộc vào nhiệm vụ :-) Để khớp chính xác tất cả các ký tự Latinh và các phiên bản có dấu của chúng, phạm vi Unicode có thể cung cấp giải pháp tốt nhất. Chúng có thể được mở rộng cho tất cả các ký tự không phải khoảng trắng, có thể được thực hiện bằng cách sử dụng \Slớp ký tự.

Tôi đang buộc một trường trong giao diện người dùng phải khớp với định dạng: last_name, first_name(lần cuối [dấu phẩy] trước)

Vấn đề cơ bản nhất tôi thấy ở đây không phải là dấu phụ, mà là khoảng trắng. Có một vài tên bao gồm nhiều từ, ví dụ như tiêu đề. Vì vậy, bạn nên đi với cái chung nhất, đó là cho phép mọi thứ trừ dấu phẩy phân biệt trước với tên cuối cùng:

/[^,]+,\s[^,]+/

Nhưng giải pháp thứ hai của bạn với .lớp nhân vật cũng tốt như vậy, bạn chỉ cần quan tâm đến nhiều dấu phẩy sau đó.


Hừm, có lẽ bạn đúng. Tôi có thể quá phức tạp nó ... Bạn có thể giải thích regex bạn cung cấp? Tôi đã làm việc với regex được một thời gian rồi, nhưng chỉ là những thứ cơ bản và thực sự tôi không biết bạn thực sự làm gì! Hà
Chris Cirefice

Đó là một lớp nhân vật bị phủ định - có nghĩa là "bất cứ điều gì ngoài dấu phẩy".
Bergi

Ah, vậy nó đọc như thế any_character_not_a_comma, any_character_not_a_commanào? Đó là những gì tôi nghĩ khi lần đầu tiên đọc nó, tôi đã bối rối khi thấy ba dấu phẩy ở đó.
Chris Cirefice

Đúng chính xác. Xin lỗi vì sự nhầm lẫn với các thiếu scho khoảng trắng ...
Bergi

1
@ MateoTibaquirá Bạn có thể đơn giản hóa [^\s]đến\S
Bergi

15

Các XRegExp thư viện có một plugin tên Unicode giúp giải quyết công việc như thế này.

<script src="xregexp.js"></script>
<script src="addons/unicode/unicode-base.js"></script>
<script>
  var unicodeWord = XRegExp("^\\p{L}+$");

  unicodeWord.test("Русский"); // true
  unicodeWord.test("日本語"); // true
  unicodeWord.test("العربية"); // true
</script>

Nó được đề cập trong các ý kiến ​​cho câu hỏi, nhưng nó rất dễ bỏ lỡ. Tôi đã nhận thấy nó chỉ sau khi tôi gửi câu trả lời này.


Thật tuyệt, hóa ra tôi không thực sự cần phải regex trên unicode, mà là trên mẫu anything, anything. Điều này sẽ hữu ích cho độc giả trong tương lai :)
Chris Cirefice

12

Còn cái này thì sao?

/^[a-zA-ZÀ-ÖØ-öø-ÿ]+$/

2
Không phù hợp Šš.
Gajus

5

Cái này thì sao?

^([a-zA-Z]|[à-ú]|[À-Ú])+$

Nó sẽ phù hợp với mọi từ có ký tự có dấu hay không.


2
Nhưng OP muốn cho phép các ký tự có dấu.
barbsan


3
/^[\pL\pM\p{Zs}.-]+$/u

Giải trình:

  • \pL - phù hợp với bất kỳ loại thư từ bất kỳ ngôn ngữ
  • \pM - tạo ra một ký tự dự định kết hợp với một ký tự khác (ví dụ: dấu, ô, hộp kèm theo, v.v.)
  • \p{Zs} - khớp với một ký tự khoảng trắng vô hình, nhưng chiếm không gian
  • u - Chuỗi mẫu và chủ đề được coi là UTF-8

Không giống như regex được đề xuất khác (chẳng hạn như [A-Za-zÀ-ÖØ-öø-ÿ]), điều này sẽ hoạt động với tất cả các ký tự cụ thể của ngôn ngữ, ví dụ: Ššđược khớp với quy tắc này, nhưng không khớp với các quy tắc khác trên trang này.

Thật không may, JavaScript vốn không hỗ trợ các lớp này. Tuy nhiên, bạn có thể sử dụng xregexp, vd

const XRegExp = require('xregexp');

const isInputRealHumanName = (input: string): boolean => {
  return XRegExp('^[\\pL\\pM-]+ [\\pL\\pM-]+$', 'u').test(input);
};

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.