将泰国名字解析为第一个最后一个

Posted

技术标签:

【中文标题】将泰国名字解析为第一个最后一个【英文标题】:Parse Thai Name into First Last 【发布时间】:2019-01-17 14:42:20 【问题描述】:

我需要将全名列表解析为名字和姓氏。如果包含中间名,则应将其包含在第一个名称字段中。

约翰·史密斯将是:

名字 = 约翰

姓氏 = 史密斯

约翰·J·史密斯将是:

名字 = John J.

姓氏 = 史密斯

问题是名称可能是泰语或英语字符集。我需要正确解析任何一组。我几乎什么都试过了……

DECLARE @FullName NVARCHAR(MAX) = N'กล้วยไม้ สวามิวัศดุ์'
--DECLARE @FullName NVARCHAR(MAX) = N'Mark C. Wilson'

SELECT 
    LEN(@FullName) AS StringLength,
    LEN(@FullName) - LEN(REPLACE(@FullName,N' ', N'')),
    LEN(REPLACE(@FullName,N' ', N'')),
    @FullName AS FullName,
    REVERSE(@FullName) AS ReverseName, -- This is obviously no Reverse of the string
    CHARINDEX(N' ', REVERSE(@FullName)) AS LastSpaceLocation,
    CHARINDEX(N' ', @FullName) AS FirstSpaceLocation,
    LEN(@FullName) AS LenString,
    STUFF(@FullName, 1, CHARINDEX(N' ', @FullName), N'') as FirstName,
    RIGHT(@FullName, LEN(@FullName) - CHARINDEX(N' ', @FullName) + 1) as LastName,
    LEFT(@FullName, LEN(@FullName) - CHARINDEX(N' ', REVERSE(@FullName))) AS FirstName,
    STUFF(RIGHT(@FullName, CHARINDEX(N' ', REVERSE(@FullName))),1,1,N'') AS LastName,
    LEN(@FullName),
    REVERSE(@FullName),
    REVERSE(' '),
    LEN(@FullName) - CHARINDEX(reverse(' '), REVERSE(@FullName)) - LEN(' ') + 1

REVERSE 在使用泰语字符集时根本不起作用。

【问题讨论】:

发生这种情况是因为颠倒泰语名称会破坏组合字符,这些字符会“附加”到空格上,导致简单的字典搜索失败。在某种程度上,您可以通过强制二进制排序规则 (SELECT CHARINDEX(N' ', REVERSE(N'กล้วยไม้ สวามิวัศดุ์') COLLATE Latin1_General_BIN2)) 来“解决”这个问题,但您很可能会遇到其他奇怪的问题。一旦你开始扩展到更多的语言(比如日语,或其他名称成分的顺序与英语不同的语言,或者根本没有姓氏),它只会变得更难。考虑尽可能不留下姓名。 您似乎有already asked 这个问题,现有的答案表明您基于反转字符串的方法存在根本缺陷,应该进行修改。很明显,自提出原始问题以来,您已经改进了查询,但问题保持不变;所以你可能需要编辑原来的 Q 而不是问一个新的。 VTC/重复。 SQL Server Parsing Thai Language Full Name to First Last的可能重复 我看到了这个,它不是我的问题的有效解决方案。 Reverse() 无法正常使用字符集。 【参考方案1】:

我不懂泰语(我没那么聪明),但也许这会有所帮助。

这里我们使用CROSS APPLY来“修复”字符串,然后是PasrName()Concat()的小事

我应该补充一点,解析名称是一个滑坡。需要考虑

多字姓氏,即 De la Cruz 后缀即。理查德 R 卡佩莱蒂医学博士

示例

Declare @YourTable table (FullName nvarchar(100))
Insert Into @YourTable values
 ('John Smith')
,('John J. Smith')
,(N'กล้วยไม้ สวามิวัศดุ์')

Select A.*
      ,LastName  = replace(parsename(S,1),'|','.')
      ,FirstName = replace(concat(parsename(S,4),' '+parsename(S,3),' '+parsename(S,2)),'|','.')
 From  @YourTable A
 Cross Apply ( values (replace(replace(FullName,'.','|'),' ','.'))) B(S)

退货

FullName          LastName    FirstName
John Smith        Smith       John
John J. Smith     Smith       John J.
กล้วยไม้ สวามิวัศดุ์    สวามิวัศดุ์     กล้วยไม้

EDIT 2008 版

Select A.*
      ,LastName  = replace(parsename(S,1),'|','.')
      ,FirstName = replace( IsNull(parsename(S,4),'') + IsNull(' '+parsename(S,3),'') + IsNull(' '+parsename(S,2),''),'|','.')
 From  @YourTable A
 Cross Apply ( values (replace(replace(FullName,'.','|'),' ','.'))) B(S)

【讨论】:

我很抱歉,但不幸的是,这是在 SS 2008 数据库中。我意识到这已经接近尾声,但是......无论如何,concat 是在 SQL Server 2012 中引入的。 @Mark:幸运的是,CONCAT 在这种情况下只是为了方便处理NULLs。用+ 连接字符串并用ISNULL(..., '') 包装连接的表达式可以降级。 @Mark Seed EDIT 2008 版 @Mark 只是说... 2008 年的扩展支持将于 2019 年 7 月结束。请将您的问题标记为 2008 年以避免假设。【参考方案2】:

我是泰国人,我知道的一件事是泰国人不使用中间名。

【讨论】:

有趣的事实......没有中间名的事情 我是荷兰人,我有两个。我从不提及它们,因为我不希望任何代码都能正确处理,尤其是数据库代码。 :-)

以上是关于将泰国名字解析为第一个最后一个的主要内容,如果未能解决你的问题,请参考以下文章

为啥布局组上实例化的最后一个元素显示为第一个且错误?

为第一个和最后一个菜单项指定唯一类

PHP 为第一个和最后一个菜单项分配唯一的类

Angular 6 *ngFor 为第一个,奇数,偶数和最后一个显示不同的样式

mysql ifnull 函数 使用和 if 三目运算

POJ 6048 泰国佛塔 dfs搜索疯狂剪枝!北大ACM/ICPC竞赛训练