拉丁字符检查

9

虽然有一些类似的问题,但没有一个完全相同或适用于我的答案。

我需要一个JavaScript函数,用于验证文本字段是否包含所有有效的拉丁字符,因此不包括西里尔文或中文,仅限拉丁文。具体来说:

基本拉丁文(不包括C0控制字符),拉丁-1(不包括C1控制字符),拉丁扩展A,拉丁扩展B和拉丁扩展附加。该集合对应于Unicode代码点U+0020到U+007E,U+00A0到U+024F和U+IE00到U+IEFF

其中一些答案似乎检查文本字段中的第一个字符,但会忽略其他字符,因此这些都不好用。

这是我迄今为止尝试过的内容(这不起作用!):

var value = 'abcdef' // from text field
var re = '\u0000-\u007F|\u0100-\u017F|\u0180-\u024F|\u1E00-\u1EFF|\u0080-\u00FF'; // latin regexp string
// var re = '\\w+/'; // alternative
if (new RegExp(re).test(value)) {
    result = false;
}

以下方式可以对第一个字符进行排序,但是对其它字符无效:
//var re = '\u0000-\u007F|\u0100-\u017F|\u0180-\u024F|\u1E00-\u1EFF|\u0080-\u00FF'; // latin regexp string
// couldn't get the above to work so using the following:
var re = '\\w+';
if (!value.match(re)) {
    message = 'Please enter valid latin characters only';
    $focusField = $this;
}

怎么做是正确的?

我真的需要代码,而不是解释,但两者都更好。

谢谢


1
SO的答案应该始终包括解释,以便下一个遇到相同问题的人能够理解。 - Alnitak
你的代码有错误,因为你试图使用块属性而不是脚本属性。你还忘记了两个块。请查看我的答案,了解正确的操作方式以及原因。 - tchrist
3个回答

17

编辑:请注意,接受答案中给出的解决方案是不正确的。它充满了错误的阳性和阴性。此帖底部提供了所需的确切数字代码点号。

问题中给出的示例错误地尝试使用块而不是脚本属性!

您不想在此处使用Unicode块字符属性;您要使用Unicode脚本字符属性。换句话说,您真正想要的是Script=Latin不是尝试使用Block=Basic_Latin加上Block=Latin_1加上Block=Latin_1_Supplement加上Block=Latin_Extended_A加上Block=Latin_Extended_Additional

还要注意,问题忽略了其他拉丁语块:Block=Latin_Extended_CBlock=Latin_Extended_D

即使您使用了正确的块,也会得到145个错误阳性,这些阳性位于那些不是拉丁文字母的块中:

$ unichars '\P{Script=Latin}' '[\p{Block=Basic_Latin}\p{Block=Latin_1}\p{Block=Latin_1_Supplement}\p{Block=Latin_Extended_A}\p{Block=Latin_Extended_B}
\p{Block=Latin_Extended_Additional}\p{Block=Latin_Extended_C}\p{Block=Latin_Extended_D}]' | wc -l
145

此外,您将错过403个错误的负面结果,它们确实是拉丁文字母,但不在那些区块中。
$ unichars '\p{Script=Latin}' '[^\p{Block=Basic_Latin}\p{Block=Latin_1}\p{Block=Latin_1_Supplement}\p{Block=Latin_Extended_A}\p{Block=Latin_Extended_B
}\p{Block=Latin_Extended_Additional}\p{Block=Latin_Extended_C}\p{Block=Latin_Extended_D}]' | wc -l
403

你几乎永远不会使用块,而是使用脚本。这就是为什么UTS#18的一级符合性要求在Requirement 1.2中要求支持脚本字符属性,但在Requirement 2.7: Full Properties中没有提到块属性的原因。
请参见UTS#18 Annex A, Character Blocks,了解使用块而不是脚本可能遇到的更多问题。
由于Javascript的错误使得无法通过范围指定超出基本多语言平面的代码点,因此我们需要删除这些代码点,然后得到以下一组难以维护的乱码,以便捞出所有具有拉丁、通用或继承脚本字符属性的Unicode v6.2代码点:
[\u0000-\u0040][\u0041-\u005A][\u005B-\u0060][\u0061-\u007A][\u007B-\u00A9]\u00AA[\u00AB-\u00B9]\u00BA[\u00BB-\u00BF][\u00C0-\u00D6]\u00D7[\u00D8-\u00
F6]\u00F7[\u00F8-\u02B8][\u02B9-\u02DF][\u02E0-\u02E4][\u02E5-\u02E9][\u02EC-\u02FF][\u0300-\u036F]\u0374\u037E\u0385\u0387[\u0485-\u0486]\u0589\u060C
\u061B\u061F\u0640[\u064B-\u0655][\u0660-\u0669]\u0670\u06DD[\u0951-\u0952][\u0964-\u0965]\u0E3F[\u0FD5-\u0FD8]\u10FB[\u16EB-\u16ED][\u1735-\u1736][\u
1802-\u1803]\u1805[\u1CD0-\u1CD2]\u1CD3[\u1CD4-\u1CE0]\u1CE1[\u1CE2-\u1CE8][\u1CE9-\u1CEC]\u1CED[\u1CEE-\u1CF3]\u1CF4[\u1CF5-\u1CF6][\u1D00-\u1D25][\u
1D2C-\u1D5C][\u1D62-\u1D65][\u1D6B-\u1D77][\u1D79-\u1DBE][\u1DC0-\u1DE6][\u1DFC-\u1DFF][\u1E00-\u1EFF][\u2000-\u200B][\u200C-\u200D][\u200E-\u2064][\u
206A-\u2070]\u2071[\u2074-\u207E]\u207F[\u2080-\u208E][\u2090-\u209C][\u20A0-\u20BA][\u20D0-\u20F0][\u2100-\u2125][\u2127-\u2129][\u212A-\u212B][\u212
C-\u2131]\u2132[\u2133-\u214D]\u214E[\u214F-\u215F][\u2160-\u2188]\u2189[\u2190-\u23F3][\u2400-\u2426][\u2440-\u244A][\u2460-\u26FF][\u2701-\u27FF][\u
2900-\u2B4C][\u2B50-\u2B59][\u2C60-\u2C7F][\u2E00-\u2E3B][\u2FF0-\u2FFB][\u3000-\u3004]\u3006[\u3008-\u3020][\u302A-\u302D][\u3030-\u3037][\u303C-\u30
3F][\u3099-\u309A][\u309B-\u309C]\u30A0[\u30FB-\u30FC][\u3190-\u319F][\u31C0-\u31E3][\u3220-\u325F][\u327F-\u32CF][\u3358-\u33FF][\u4DC0-\u4DFF][\uA70
0-\uA721][\uA722-\uA787][\uA788-\uA78A][\uA78B-\uA78E][\uA790-\uA793][\uA7A0-\uA7AA][\uA7F8-\uA7FF][\uA830-\uA839][\uFB00-\uFB06][\uFD3E-\uFD3F]\uFDFD
[\uFE00-\uFE0F][\uFE10-\uFE19][\uFE20-\uFE26][\uFE30-\uFE52][\uFE54-\uFE66][\uFE68-\uFE6B]\uFEFF[\uFF01-\uFF20][\uFF21-\uFF3A][\uFF3B-\uFF40][\uFF41-\
uFF5A][\uFF5B-\uFF65]\uFF70[\uFF9E-\uFF9F][\uFFE0-\uFFE6][\uFFE8-\uFFEE][\uFFF9-\uFFFD]

就我个人而言,我会解雇任何试图使用那种无聊说法的人。

此外,由于Javascript处理完整Unicode时存在的错误,您错过了3,225个代码点,它们如下:

10100-10102 10107-10133 10137-1013F 10190-1019B 101D0-101FC 101FD
1D000-1D0F5 1D100-1D126 1D129-1D166 1D167-1D169 1D16A-1D17A 1D17B-1D182
1D183-1D184 1D185-1D18B 1D18C-1D1A9 1D1AA-1D1AD 1D1AE-1D1DD 1D300-1D356
1D360-1D371 1D400-1D454 1D456-1D49C 1D49E-1D49F 1D4A2 1D4A5-1D4A6
1D4A9-1D4AC 1D4AE-1D4B9 1D4BB 1D4BD-1D4C3 1D4C5-1D505 1D507-1D50A
1D50D-1D514 1D516-1D51C 1D51E-1D539 1D53B-1D53E 1D540-1D544 1D546
1D54A-1D550 1D552-1D6A5 1D6A8-1D7CB 1D7CE-1D7FF 1F000-1F02B 1F030-1F093
1F0A0-1F0AE 1F0B1-1F0BE 1F0C1-1F0CF 1F0D1-1F0DF 1F100-1F10A 1F110-1F12E
1F130-1F16B 1F170-1F19A 1F1E6-1F1FF 1F201-1F202 1F210-1F23A 1F240-1F248
1F250-1F251 1F300-1F320 1F330-1F335 1F337-1F37C 1F380-1F393 1F3A0-1F3C4
1F3C6-1F3CA 1F3E0-1F3F0 1F400-1F43E 1F440 1F442-1F4F7 1F4F9-1F4FC
1F500-1F53D 1F540-1F543 1F550-1F567 1F5FB-1F640 1F645-1F64F 1F680-1F6C5
1F700-1F773 E0001 E0020-E007F E0100-E01EF

以下是正确的操作方法。
如果您要处理Unicode字符属性,硬编码代码点号几乎是无望的。您真正想要的是能够像这样说:
[^\p{Script=Latin}\p{Script=Common}\p{Script=Inherited}]

然而,JavaScript正则表达式在这方面仍然完全落后,甚至远未达到Unicode技术标准#18:Unicode正则表达式最基本的兼容级别,第一级要求:

第一级:基本Unicode支持。 在此级别上,正则表达式引擎提供对Unicode字符的支持作为基本逻辑单元。(这独立于Unicode的实际序列化方式,如UTF-8、UTF-16BE、UTF-16LE、UTF-32BE或UTF-32LE。)这是有用的Unicode支持的最低级别。它不考虑最终用户对字符支持的期望,但可以满足大多数低级程序员的需求。在该级别上,正则表达式匹配的结果与国家或语言无关。在此级别上,正则表达式引擎的用户需要编写更复杂的正则表达式才能进行完整的Unicode处理。

因为即使是Unicode正则表达式的最基本兼容级别仍然远远低于JavaScript的能力,我强烈建议在支持它们的某种语言的服务器上运行您需要的任何Unicode感知的正则表达式。
然而,如果这不可行,一种节省精神的解决方法是Javascript XRegExp插件,它提供了一个更合理的正则表达式库,还允许访问某些必要的字符属性,例如您正在尝试使用的属性。
从v2.0开始,“XRegExp All”附加组件支持所有这些内容:
  • XRegExp 2.0.0
  • Unicode Base 1.0.0
  • Unicode Categories 1.2.0
  • Unicode Scripts 1.2.0
  • Unicode Blocks 1.2.0
  • Unicode Properties 1.0.0
  • XRegExp.matchRecursive 0.2.0
  • XRegExp.build 0.1.0
  • Prototypes 1.0.0
这意味着一旦加载了它,您将能够以以下方式获取所需的属性:
XRegExp("[^\\p{Latin}\\p{Common}\\p{Inherited}]");

请注意,从Unicode v6.2开始,以下所有代码点和代码点范围都被视为具有“Script=Latin”字符属性:
0041-005A 
0061-007A 
00AA 
00BA 
00C0-00D6 
00D8-00F6 
00F8-02B8 
02E0-02E4 
1D00-1D25 
1D2C-1D5C 
1D62-1D65 
1D6B-1D77 
1D79-1DBE 
1E00-1EFF 
2071 
207F 
2090-209C 
212A-212B 
2132 
214E 
2160-2188 
2C60-2C7F 
A722-A787 
A78B-A78E 
A790-A793 
A7A0-A7AA 
A7F8-A7FF 
FB00-FB06 
FF21-FF3A 
FF41-FF5A 

以下是具有字符属性Script=Common的代码点:
0000-0040  
005B-0060  
007B-00A9  
00AB-00B9  
00BB-00BF  
00D7
00F7
02B9-02DF  
02E5-02E9  
02EC-02FF  
0374
037E
0385 
0387
0589
060C
061B
061F
0640
0660-0669  
06DD
0964-0965  
0E3F 
0FD5-0FD8  
10FB
16EB-16ED
1735-1736
1802-1803
1805
1CD3
1CE1
1CE9-1CEC
1CEE-1CF3
1CF5-1CF6
2000-200B
200E-2064
206A-2070  
2074-207E  
2080-208E  
20A0-20BA  
2100-2125
2127-2129
212C-2131  
2133-214D  
214F-215F  
2189
2190-23F3
2400-2426
2440-244A
2460-26FF
2701-27FF
2900-2B4C
2B50-2B59
2E00-2E3B
2FF0-2FFB  
3000-3004
3006
3008-3020
3030-3037  
303C-303F
309B-309C
30A0
30FB-30FC
3190-319F
31C0-31E3
3220-325F
327F-32CF
3358-33FF
4DC0-4DFF
A700-A721
A788-A78A
A830-A839
FD3E-FD3F  
FDFD
FE10-FE19  
FE30-FE52
FE54-FE66
FE68-FE6B  
FEFF
FF01-FF20  
FF3B-FF40
FF5B-FF65
FF70
FF9E-FF9F
FFE0-FFE6
FFE8-FFEE
FFF9-FFFD
10100-10102
10107-10133
10137-1013F
10190-1019B
101D0-101FC
1D000-1D0F5
1D100-1D126
1D129-1D166
1D16A-1D17A
1D183-1D184
1D18C-1D1A9
1D1AE-1D1DD
1D300-1D356
1D360-1D371
1D400-1D454
1D456-1D49C
1D49E-1D49F
1D4A2
1D4A5-1D4A6
1D4A9-1D4AC
1D4AE-1D4B9
1D4BB
1D4BD-1D4C3
1D4C5-1D505
1D507-1D50A
1D50D-1D514
1D516-1D51C
1D51E-1D539
1D53B-1D53E
1D540-1D544
1D546
1D54A-1D550
1D552-1D6A5
1D6A8-1D7CB
1D7CE-1D7FF
1F000-1F02B
1F030-1F093
1F0A0-1F0AE
1F0B1-1F0BE
1F0C1-1F0CF
1F0D1-1F0DF
1F100-1F10A
1F110-1F12E
1F130-1F16B
1F170-1F19A
1F1E6-1F1FF
1F201-1F202
1F210-1F23A
1F240-1F248
1F250-1F251
1F300-1F320
1F330-1F335
1F337-1F37C
1F380-1F393
1F3A0-1F3C4
1F3C6-1F3CA
1F3E0-1F3F0
1F400-1F43E
1F440
1F442-1F4F7
1F4F9-1F4FC
1F500-1F53D
1F540-1F543
1F550-1F567
1F5FB-1F640
1F645-1F64F
1F680-1F6C5
1F700-1F773
E0001
E0020-E007F

以下是具有Script=Inherited字符属性的代码点:
0300-036F
0485-0486
064B-0655
0670
0951-0952
1CD0-1CD2
1CD4-1CE0
1CE2-1CE8
1CED
1CF4
1DC0-1DE6
1DFC-1DFF
200C-200D
20D0-20F0
302A-302D
3099-309A
FE00-FE0F
FE20-FE26
101FD
1D167-1D169
1D17B-1D182
1D185-1D18B
1D1AA-1D1AD
E0100-E01EF

我希望你能意识到使用像这样的文字码点数字会导致可维护性、可读性和可写性等问题,因此请至少使用XRegExp附加组件来解决这些问题。


我知道答案,但您介意解释一下为什么应该在搜索中包括Common和Inherited脚本吗? - R. Martinho Fernandes
被接受的答案并没有错误,它很有效。你的回答并没有解释我的问题或提供解决方案。 - CompanyDroneFromSector7G
@bukko 嗯,这个答案提供了一种使用名为XRegExp的第三方库的解决方案,该库支持表示所有拉丁字符的特定代码点号集。然而,在我看来,从某种意义上说,它过于复杂化了基本思想。 - VisioN
3
@bukko请查看编辑后有关使用区块而不是脚本的问题。 - tchrist
1
这是一份非常详细的信息,解释得非常好。谢谢 :) - CompanyDroneFromSector7G
这实际上是我最终所做的。 - CompanyDroneFromSector7G

3

我正在使用:

/^[A-z\u00C0-\u00ff\s'\.,-\/#!$%\^&\*;:{}=\-_`~()]+$/

作为正则表达式。我没有测试所有选项,但我已经使用了多年,从未遇到任何问题。

var regexp = /[A-z\u00C0-\u00ff]+/g,
  ascii = ' hello !@#$%^&*())_+=',
  latin = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏàáâãäåæçèéêëìíîïÐÑÒÓÔÕÖØÙÚÛÜÝÞßðñòóôõöøùúûüýþÿ',
  chinese = ' 你 好 ';

console.log(regexp.test(ascii)); // true
console.log(regexp.test(latin)); // true
console.log(regexp.test(chinese)); // false

Glist: https://gist.github.com/germanattanasio/84cd25395688b7935182

的意思是,它是一个指向GitHub上Gist页面的链接。在该页面中,您可以找到有关IT技术的相关信息和代码示例。请点击链接以获取更多信息。

1

可能的一种实现方式:

if (/[^\u0020-\u007F\u00A0-\u024F\u1E00-\u1EFF]/.test(value)) {
    // non latin characters found
}

正则表达式测试不在集合[]中的字符,该集合包括\u0020-\u007F\u00A0-\u024F\u1E00-\u1EFF组。


太棒了 - 如果你把感叹号去掉的话 ;) 谢谢 - CompanyDroneFromSector7G
@bukko 很抱歉,那些数字是错误的。请看我的答案。 - tchrist
1
那句老话是怎么说的来着?“如果代码和注释不一致,两者都是错误的。” :) 我看到问题了:用户正在不适当地尝试使用块属性而不是脚本属性,而他实际上需要的是脚本属性。 - tchrist
1
你在叫谁是用户? - CompanyDroneFromSector7G
不是拉丁文,但仍然继续使用此解决方案,因此它不起作用。 - Oleg Sapishchuk
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接