在Active Record Callback中验证日语字符

时间:2013-03-26 07:00:54

标签: ruby-on-rails ruby validation rails-activerecord cjk

我有一个需要验证半宽和全宽日文字符的日文项目,半宽度允许14个字符,全宽度允许7个字符。

有谁知道如何实现它?

现在我的模特

class Customer
   validates_length_of :name, :maximum => 14
end

不是一个好选择

我目前正在使用ror 2.3.5 可以使用全宽和半宽

2 个答案:

答案 0 :(得分:10)

首先,全角(全角)和半角(半角)的概念仅适用于日语中的两种字符:

  • 罗马字符(即拉丁文)
  • 片假名字符

韩国朝鲜族也存在类似的概念,但日语平假名和汉字并不存在。

对于片假名,半角字符有自己的Unicode代码点,它们的大小是全角字符的一半,但它们的形状相同。例如:

全宽“ka”:カ
半宽“ka”:カ

组合字符(即ガ等变音符号)在半宽版本中不存在;它们必须被编码为两个单独的字符:カ+゙,这可能是你的任务中允许两倍宽度的两倍字符的原因。 (请注意,这两个代码点的组合被视为组合字符,通常呈现为一个。)

对于罗马(拉丁)字符,通常的ASCII字符称为半宽,但Unicode的日语代码范围(以及传统的日本特定字符集)为全宽提供单独的代码范围版本。例如:

全宽:L
半宽:L

非ASCII拉丁语派生字符(例如德语变音符号)和重音版本不存在全宽版本。但是,它们存在数字和一些标点字符。

同样,平假名和汉字没有半宽版本。

要检查字符是全角还是半字符,请将代码点与相关代码范围进行比较。范围如下:

半角片假名:0xff610xff9f
全宽片假名:0x30a00x30ff
Halfwidth Roman:0x210x7e(这是ASCII)
全宽罗马:0xff010xff60
平假名:0x30410x309f
汉字(即统一表意符号范围):0x4e000x9fcc

这是一个简单的Ruby程序,它基于每个字符执行检查:

# -*- coding: utf-8 -*-

def is_halfwidth_katakana(c)
  return (c.ord >= 0xff61 and c.ord <= 0xff9f)
end

def is_fullwidth_katakana(c)
  return (c.ord >= 0x30a0 and c.ord <= 0x30ff)
end

def is_halfwidth_roman(c)
  return (c.ord >= 0x21 and c.ord <= 0x7e)
end

def is_fullwidth_roman(c)
  return (c.ord >= 0xff01 and c.ord <= 0xff60)
end

def is_hiragana(c)
  return (c.ord >= 0x3041 and c.ord <= 0x309f)
end

def is_kanji(c)
  return (c.ord >= 0x4e00 and c.ord <= 0x9fcc)
end

text = "Hello World、こんにちは、半角カタカナ、全角カタカナ、fullwidth 0-9\n"

text.split("").each do |c|
  if is_halfwidth_katakana(c)
    type = "halfwidth katakana"
  elsif is_fullwidth_katakana(c)
    type = "fullwidth katakana"
  elsif is_halfwidth_roman(c)
    type = "halfwidth roman"
  elsif is_fullwidth_roman(c)
    type = "fullwidth roman"
  elsif is_hiragana(c)
    type = "hiragana"
  elsif is_kanji(c)
    type = "kanji"
  end

  printf("%c (%x) %s\n",c,c.ord,type)
end

进一步说明

  1. 上面的代码范围是每种字符类型的官方Unicode范围(请参阅Unicode Fullwidth formsUnicode Hiragana)。这些包括旧/传统形式或特殊标点字符的某些全宽/半宽版本的字符。如果您只想要在Web表单中常用的字符(例如,人们输入其名称),您可能希望稍微缩小范围。

  2. 建议:如果这是针对人们可以输入姓名的网络表单,您可能需要做的不仅仅是检查半宽或全宽。它在日本的网站和注册表格上非常普遍,尤其是与银行一起要求人们以纯半宽(通常为拉丁语)或纯全宽(通常为片假名)输入其名称。不幸的是,这使得输入数据非常不方便。启用日语输入法时,拉丁字符通常以全宽版本出现,然后Web表单将拒绝数据,因为它不是纯半宽。它应该自动将其转换为它需要的任何形式,而不是拒绝它。您可以通过从一个代码范围转换到另一个代码范围(只需添加相关常量)轻松实现这一点,并使人们的生活更加轻松。

答案 1 :(得分:5)

以下代码可能只是为了满足您在最短时间内指定的完全要求 。它使用Moji gemJapanese documentation),它在确定日语字符串的内容时提供了许多方便的方法。

它验证name中最多14个字符由半角字符组成,否则name最多包含7个字符(包括名称)包含半角和全角字符的组合,即字符串中甚至一个全角字符的存在将使整个字符串被视为“全宽”。

class Customer 

  validates_length_of :name, :maximum => 14, 
    :if => Proc.new { |customer| half_width?(customer.name) }
  validates_length_of :name, :maximum => 7
    :unless => Proc.new { |customer| half_width?(customer.name) }

  def half_width?(string)
    Moji.type?(string, Moji::HAN_KATA)
  end

end

做出的假设

  1. 系统内的数据编码为UTF-8,并在数据库中存储;任何进一步必要的重新编码(例如将数据传递到遗留系统等)都在另一个模块中完成。
  2. 在将数据保存到数据库之前不会自动转换半到全角字符,即数据库中允许使用半角字符,原因可能是遗留系统集成,正确保存实际用户输入(!),以及/或半角字符的美学价值(!)
  3. 半角字符中的变音符号被视为它们自己的单独字符(即,为了确定字符串长度,不会将カ和pars解析为一个字符)
  4. 您指定的名称字段只有一个,而不是,例如,四个(姓氏,姓氏furigana,给定名称,名称为furigana),这在当今很常见。