重音字符的具体Javascript正则表达式(变音符号)


166

我已经研究了Stack Overflow(替换字符。ehJavaScript如何不遵循有关RegExp的Unicode标准等),还没有真正找到问题的具体答案:

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

我正在强制UI中的字段匹配以下格式:(last_name, first_name 最后一个[逗号空间]首先),并且我想提供对变音符号的支持,但是显然在JavaScript中,它比其他语言/平台要难一些。

这是我的原始版本,直到我想添加变音符号支持:

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

目前,我正在讨论增加支持的三种方法之一,所有这些方法我都已经过测试和工作(至少在某种程度上,我真的不知道第二种方法的“范围”是什么)。他们来了:

明确列出我希望接受的所有带重音符号的字符(花边和过于复杂):


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àèìòùÀÈÌÒÙáéíóúýÁÉÍÓÚÝâêîôûÂÊÎÔÛãñõÃÑÕäëïöüÿÄËÏÖÜŸçÇßØøÅåÆæœ]+$/
  • 这样可以正确地将姓氏/名字与中的任何支持的重音字符相匹配accentedCharacters

我的另一种方法是使用.字符类,使表达式更简单:

var regex = /^.+,\s.+$/;
  • 这几乎可以匹配任何东西,至少形式为:something, something。我想那没关系...

我刚刚发现的最后一种方法可能更简单...

/^[a-zA-Z\u00C0-\u017F]+,\s[a-zA-Z\u00C0-\u017F]+$/
  • 它与一系列unicode字符匹配-经过测试和正常工作,尽管我没有做任何疯狂的事情,但仅仅是我在语言部门中看到的用于教师姓名的普通内容。

这是我的担忧:

  1. 第一个解决方案太过局限了,草率而又令人费解。如果我忘了一个或两个字符,则需要更改它,但这不是很实际。
  2. 第二种解决方案更好,更简洁,但是它可能比实际需要的匹配得多。我找不到任何实际的文件究竟是什么.比赛,(在从表中“任何除换行符字符”的只是概括MDN)。
  3. 第三种解决方案似乎是最精确的,但是有什么陷阱吗?我不是很熟悉的Unicode,在实践中至少,但看着码表 / 该表的延续\u00C0-\u017F似乎是非常稳固,至少在我的预期输入。

    • 学院不会以其母语(例如阿拉伯语,中文,日语等)提交带有名称的表格,因此我不必担心拉丁字符集字符超出

因此,真正的问题是:这三种方法中哪一种最适合该任务?还是有更好的解决方案?


1
似乎没有特别的理由使用更复杂的正则表达式。关于最简单的解决方案的唯一问题是,它也将匹配“某物,某物,某物”。您可以使用类似的方法regex = /^[^,]+,\s[^,]+$/;来防止这种情况。
usr2564301 2013年

4
乍一看,第一个名字不会与通用名称“ O'Donnell,Chris”匹配,也不会与连字号混合姓氏,也不会匹配多个姓氏(等等)。有关每种可能的陷阱,请参见虚假程序员相信名称
usr2564301 2013年

.原子匹配任何东西,除了换行 ”其实是相当准确的:-)
BERGI

1
如果您可以使用其他库,则可以在此处
13年

Jongware,我实际上是在浏览SO时读到该文章的,以寻求对我的问题的答案-我也完全忘记了连字符和撇号之类的东西,我更关心将其国际化:P很高兴您带来它起来!还有Stema,我实际上查看了该库,因此避免合并库,因为这全在Google Apps脚本上-合并外部库将是一场噩梦,并且(在这种情况下)我只会在特定领域使用它...过大的杀伤力:P
克里斯·西里菲斯

Answers:


275

接受所有重音的更简单方法是:

[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 [ ] ^ \ × ÷

有关以数字顺序列出的字符,请参见https://unicode-table.com/cn/


2
效果很好,+ 1,但您能否详细说明为什么要这样做?
皮埃尔·亨利

1
@PierreHenry -定义了一个范围,该技术利用字符集中的字符顺序来定义一个连续范围,从而为解决该问题提供了一个超简洁的解决方案
Angad

8
这会不会比赛下划线(之间的其他非单词字符Za)?
jcuenod

21
这至少与字符[,],^和\匹配,不应包含任何字符。
Nate

2
没有工作,在此范围内的几个字符不是重音字符(U + 00D7是例如乘号)看到这一点:unicode-table.com/en
杰里米Pouyet

39

拉丁字母的重音范围\u00C0-\u017F不足以容纳我的姓名数据库,因此我将正则表达式扩展为

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

我添加了以下代码块(\u00C0-\u024F一次包含三个相邻的块):

请注意,这\u00C0-\u00FF实际上只是Latin-1 Supplement的一部分。该范围将跳过无法打印的控制信号和除笨拙放置的乘除x \u00D7和除÷ 之外的所有符号\u00F7

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

如果需要更多代码点,可以在Wikipedia的Unicode字符列表中找到更多范围。例如,您还可以添加Latin Extended-CDE,但是我将它们省略了,因为现在只有历史学家似乎对它们感兴趣,并且D和E集甚至在我的浏览器中无法正确呈现。

最初的正则表达式停靠在\u017F名称“ Șenol”上。根据FontSpace的Unicode分析器,第一个字符为\u0218拉丁字母大写字母S,下面是逗号。(是的,它通常拼写为cedilla-S \u015E,“Şenol”。但是我不是要飞往土耳其告诉他,“您的名字拼写错误!”)


1
看一下unicode表的拉丁块,我认为您还应该包含\ u1e00- \ u1eff,所以我正在做[a-zA-Z\u00c0-\u024f\u1e00-\u1eff]
cprcrack

18

这三种方法中哪一种最适合该任务?

取决于任务:-)要完全匹配所有拉丁字符及其带重音的版本,Unicode范围可能提供最佳解决方案。它们可以扩展到所有非空白字符,可以使用\S字符类来完成。

我在UI中强制字段匹配以下格式:(last_name, first_name最后一个[逗号空间]首先)

我在这里看到的最基本的问题不是变音符号,而是空格。有一些名称由多个单词组成,例如标题。因此,您应该使用最通用的名称,即允许使用除以逗号区分姓氏和名字之外的所有内容:

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

但是,使用.字符类的第二种解决方案也一样,那么您只需要关心多个逗号即可。


嗯,也许你是对的。我可能过于复杂了...您能解释一下您提供的正则表达式吗?我已经在正则表达式上工作了一段时间,但仅是基本的东西,实际上我不知道您的实际操作是什么!Ha
Chris Cirefice

这是一个否定的字符类 -意思是“除逗号外的所有字符 ”。
Bergi 2013年

嗯,所以读起来更像any_character_not_a_comma, any_character_not_a_comma?这就是我初读时的想法,当我看到其中的三个逗号时,我有点困惑。
克里斯·西里菲斯

对,就是这样。对不起,缺少s空格感到困惑……
Bergi

1
@MateoTibaquirá您可以简化[^\s]\S
Bergi

15

XRegExp库有一个名为Unicode的插件,可以帮助解决这样的任务。

<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>

在问题注释中提到了它,但是很容易错过。我在提交此答案后才注意到它。


不错,事实证明,我实际上不需要在unicode上进行正则表达式,而是在pattern上进行正则表达式anything, anything。这对将来的读者很有用:)
克里斯·西里菲斯




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

说明:

  • \pL -匹配任何语言的任何字母
  • \pM -附加一个打算与另一个字符组合的字符(例如重音符号,变音符号,封闭框等)
  • \p{Zs} -匹配不可见但占用空间的空白字符
  • u -模式和主题字符串被视为UTF-8

与其他拟议的正则表达式(例如[A-Za-zÀ-ÖØ-öø-ÿ])不同,这将适用于所有特定于语言的字符,例如Šš,此规则匹配,但此页面上的其他字符则不匹配。

不幸的是,JavaScript本身不支持这些类。但是,您可以使用xregexp,例如

const XRegExp = require('xregexp');

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.