farsifu 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/Gemfile.lock +22 -1
- data/Guardfile +9 -0
- data/README.md +8 -2
- data/farsifu.gemspec +1 -0
- data/lib/farsifu/constants.rb +89 -0
- data/lib/farsifu/convert.rb +35 -0
- data/lib/farsifu/num_to_word.rb +98 -0
- data/lib/farsifu/punch.rb +40 -0
- data/lib/farsifu/version.rb +1 -1
- data/lib/farsifu/word_to_num.rb +66 -0
- data/lib/farsifu.rb +11 -453
- data/lib/iran/iran.rb +314 -0
- data/spec/farsifu_spec.rb +1 -0
- data/spec/lib/convert_spec.rb +14 -0
- data/spec/lib/iran_spec.rb +10 -0
- data/spec/lib/num_to_word_spec.rb +42 -0
- data/spec/lib/word_to_num_spec.rb +34 -0
- data/spec/spec_helper.rb +3 -1
- metadata +33 -2
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,12 +1,29 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
farsifu (0.
|
4
|
+
farsifu (0.4.0)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: http://rubygems.org/
|
8
8
|
specs:
|
9
|
+
coderay (1.0.8)
|
9
10
|
diff-lcs (1.1.3)
|
11
|
+
guard (1.6.2)
|
12
|
+
listen (>= 0.6.0)
|
13
|
+
lumberjack (>= 1.0.2)
|
14
|
+
pry (>= 0.9.10)
|
15
|
+
terminal-table (>= 1.4.3)
|
16
|
+
thor (>= 0.14.6)
|
17
|
+
guard-rspec (2.4.0)
|
18
|
+
guard (>= 1.1)
|
19
|
+
rspec (~> 2.11)
|
20
|
+
listen (0.7.2)
|
21
|
+
lumberjack (1.0.2)
|
22
|
+
method_source (0.8.1)
|
23
|
+
pry (0.9.11.4)
|
24
|
+
coderay (~> 1.0.5)
|
25
|
+
method_source (~> 0.8)
|
26
|
+
slop (~> 3.4)
|
10
27
|
rspec (2.12.0)
|
11
28
|
rspec-core (~> 2.12.0)
|
12
29
|
rspec-expectations (~> 2.12.0)
|
@@ -15,6 +32,9 @@ GEM
|
|
15
32
|
rspec-expectations (2.12.1)
|
16
33
|
diff-lcs (~> 1.1.3)
|
17
34
|
rspec-mocks (2.12.1)
|
35
|
+
slop (3.4.3)
|
36
|
+
terminal-table (1.4.5)
|
37
|
+
thor (0.17.0)
|
18
38
|
|
19
39
|
PLATFORMS
|
20
40
|
ruby
|
@@ -22,4 +42,5 @@ PLATFORMS
|
|
22
42
|
DEPENDENCIES
|
23
43
|
bundler (~> 1.2.0)
|
24
44
|
farsifu!
|
45
|
+
guard-rspec
|
25
46
|
rspec (~> 2.12.0)
|
data/Guardfile
ADDED
data/README.md
CHANGED
@@ -17,6 +17,7 @@ farsifu is a toolbox for developing ruby applications in Persian (Farsi) languag
|
|
17
17
|
-0.999.spell_farsi # => "منفی صفر ممیز نهصد و نود و نه هزارم"
|
18
18
|
12.spell_ordinal_farsi # => "دوازدهم"
|
19
19
|
12.spell_ordinal_farsi(true) # => "دوازدهمین"
|
20
|
+
"هزار و چهل و پنج".farsi_to_number # => 1045
|
20
21
|
|
21
22
|
|
22
23
|
Iran::Provinces
|
@@ -33,9 +34,14 @@ farsifu is a toolbox for developing ruby applications in Persian (Farsi) languag
|
|
33
34
|
## Install
|
34
35
|
gem install farsifu
|
35
36
|
|
36
|
-
##
|
37
|
+
## Changelog
|
38
|
+
### 0.4.0 - 4.FEB.2013
|
39
|
+
* added `farsi_to_number` to convert farsi spelling of numbers to real numbers , courtesy of [Arash Mousavi](https://github.com/arashm)
|
40
|
+
* Major refactoring and reorganization of the code, courtesy of [Arash Mousavi](https://github.com/arashm)
|
41
|
+
|
42
|
+
|
37
43
|
### 0.3.0 - 28.JAN.2013
|
38
|
-
* added farsi ordinal spelling, courtesy of Arash Mousavi
|
44
|
+
* added farsi ordinal spelling, courtesy of [Arash Mousavi](https://github.com/arashm)
|
39
45
|
|
40
46
|
|
41
47
|
### 0.2.2 - 11.APR.2011
|
data/farsifu.gemspec
CHANGED
@@ -0,0 +1,89 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module FarsiFu
|
4
|
+
PERSIAN_CHARS = "۱۲۳۴۵۶۷۸۹۰،؛"
|
5
|
+
ENGLISH_CHARS = "1234567890,;"
|
6
|
+
|
7
|
+
PERSIAN_DIGIT_JOINT = " و "
|
8
|
+
PERSIAN_DIGIT_SIGN = ["منفی ", "مثبت ", " ممیز "]
|
9
|
+
|
10
|
+
PERSIAN_DIGIT_SPELL = {
|
11
|
+
0 => [ nil ,"یک","دو","سه","چهار","پنج","شش","هفت","هشت","نه", "صفر"] ,
|
12
|
+
1 => [ nil ,"ده","بیست","سی","چهل","پنجاه","شصت","هفتاد","هشتاد","نود"],
|
13
|
+
2 => [ nil ,"صد","دویست","سیصد","چهارصد","پانصد","ششصد","هفتصد","هشتصد","نهصد"],
|
14
|
+
"10..19" => [ "ده" ,"یازده","دوازده","سیزده","چهارده","پانزده","شانزده","هفده","هجده","نوزده"],
|
15
|
+
"zillion" => [ nil ,"هزار","میلیون","میلیارد","بیلیون","تریلیون","کوادریلیون","کوینتیلیون","سیکستیلیون","سپتیلیون","اکتیلیون","نونیلیون","دسیلیون"],
|
16
|
+
"decimals" => [ nil, "دهم", "صدم", "هزارم", "دههزارم", "صدهزارم", "میلیونیم", "دهمیلیونیم","صدمیلیونیم","میلیاردیم"]
|
17
|
+
}
|
18
|
+
|
19
|
+
EXCEPTIONS = {
|
20
|
+
"یک" => 1,
|
21
|
+
"دو" => 2,
|
22
|
+
"سه" => 3,
|
23
|
+
"چهار" => 4,
|
24
|
+
"پنج" => 5,
|
25
|
+
"شش" => 6,
|
26
|
+
"هفت" => 7,
|
27
|
+
"هشت" => 8,
|
28
|
+
"نه" => 9,
|
29
|
+
|
30
|
+
"یازده" => 11,
|
31
|
+
"دوازده" => 12,
|
32
|
+
"سیزده" => 13,
|
33
|
+
"چهارده" => 14,
|
34
|
+
"پانزده" => 15,
|
35
|
+
"شانزده" => 16,
|
36
|
+
"هفده" => 17,
|
37
|
+
"هجده" => 18,
|
38
|
+
"نوزده" => 19,
|
39
|
+
|
40
|
+
"ده" => 10,
|
41
|
+
"بیست" => 20,
|
42
|
+
"سی" => 30,
|
43
|
+
"چهل" => 40,
|
44
|
+
"پنجاه" => 50,
|
45
|
+
"شصت" => 60,
|
46
|
+
"هفتاد" => 70,
|
47
|
+
"هشتاد" => 80,
|
48
|
+
"نود" => 90,
|
49
|
+
|
50
|
+
"صد" => 100,
|
51
|
+
"دویست" => 200,
|
52
|
+
"سیصد" => 300,
|
53
|
+
"چهارصد" => 400,
|
54
|
+
"پانصد" => 500,
|
55
|
+
"ششصد" => 600,
|
56
|
+
"هفتصد" => 700,
|
57
|
+
"هشتصد" => 800,
|
58
|
+
"نهصد" => 900
|
59
|
+
}
|
60
|
+
|
61
|
+
POWER_OF_TEN = {
|
62
|
+
# based on:
|
63
|
+
# https://fa.wikipedia.org/wiki/%D9%86%D8%A7%D9%85_%D8%A7%D8%B9%D8%AF%D8%A7%D8%AF_%D8%A8%D8%B2%D8%B1%DA%AF
|
64
|
+
"صفر" => 0,
|
65
|
+
"ده" => 1,
|
66
|
+
"هزار" => 3,
|
67
|
+
"میلیون" => 6,
|
68
|
+
"میلیارد" => 9,
|
69
|
+
"بیلیون" => 12,
|
70
|
+
"بیلیارد" => 15,
|
71
|
+
"تریلیون" => 18,
|
72
|
+
"تریلیارد" => 21,
|
73
|
+
"کادریلیون" => 24,
|
74
|
+
"کادریلیارد" => 27,
|
75
|
+
"کوانتینیوم" => 30,
|
76
|
+
"کوانتینیارد" => 33,
|
77
|
+
"سکستیلیون" => 36,
|
78
|
+
"سکستیلیارد" => 39,
|
79
|
+
"دسیلیون" => 42,
|
80
|
+
"سپتیلیارد" => 45,
|
81
|
+
"اکتیلیون" => 48,
|
82
|
+
"اکتیلیارد" => 51,
|
83
|
+
"نانیلیون" => 54,
|
84
|
+
"نانیلیارد" => 57,
|
85
|
+
"دسیلیون" => 60,
|
86
|
+
"دسیلیارد" => 63,
|
87
|
+
"گوگول" => 100
|
88
|
+
}
|
89
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module FarsiFu
|
2
|
+
class Convert
|
3
|
+
|
4
|
+
def initialize(number)
|
5
|
+
@number = number
|
6
|
+
end
|
7
|
+
|
8
|
+
# :startdoc:
|
9
|
+
|
10
|
+
# Returns a string which is the equivalent English number of a Persian number (in String)
|
11
|
+
#
|
12
|
+
# Example:
|
13
|
+
# "۱۲۳".to_english # => "123"
|
14
|
+
def to_english
|
15
|
+
self.to_s.tr(PERSIAN_CHARS,ENGLISH_CHARS)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Returns a string which is the equivalent Persian number of an English number (in String)
|
19
|
+
# accepts instances of String, Integer and Numeric classes (Fixnum,Bignum and floats are accepted)
|
20
|
+
#
|
21
|
+
# alias: to_persian
|
22
|
+
#
|
23
|
+
# Example:
|
24
|
+
# "123".to_farsi # => "۱۲۳"
|
25
|
+
# "456".to_persian # => "۴۵۶"
|
26
|
+
# 789.to_farsi # => "۷۸۹"
|
27
|
+
def to_farsi
|
28
|
+
self.to_s.tr(ENGLISH_CHARS,PERSIAN_CHARS)
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_s
|
32
|
+
@number.to_s
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module FarsiFu
|
4
|
+
class NumToWord
|
5
|
+
|
6
|
+
def initialize(number)
|
7
|
+
@number = number
|
8
|
+
end
|
9
|
+
|
10
|
+
# Spells a number in Persian
|
11
|
+
# accpets english numbers (in float,fixnum or string)
|
12
|
+
#
|
13
|
+
# Example:
|
14
|
+
# 5678.spell_farsi # => "پنج هزار و ششصد و هفتاد و هشت"
|
15
|
+
def spell_farsi
|
16
|
+
# Distigushing the number (float and )
|
17
|
+
if @number.class == Float
|
18
|
+
num_array = @number.to_f.to_s.split(".").first.split(//).reverse
|
19
|
+
dec_array = @number.to_f.to_s.split(".").last.split(//).slice(0..9).compact.reverse
|
20
|
+
dec_copy_b = dec_array.clone ; dec_copy_a = dec_array.clone
|
21
|
+
result = spell(num_array)
|
22
|
+
( result += PERSIAN_DIGIT_SIGN[2] + spell(dec_array) + " " + PERSIAN_DIGIT_SPELL["decimals"][dec_copy_a.size].to_s ) unless [PERSIAN_DIGIT_SPELL[0][10],""].include? spell(dec_copy_b)
|
23
|
+
return result
|
24
|
+
else
|
25
|
+
num_array = @number.to_i.to_s.split(//).reverse
|
26
|
+
return spell(num_array)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Spells numbers in sequentional format. If pass `true`, it will use the second format
|
31
|
+
#
|
32
|
+
# Example:
|
33
|
+
# 1.spell_ordinal_farsi # => "اول"
|
34
|
+
# 121.spell_ordinal_farsi # => "صد و بیست و یکم"
|
35
|
+
# 2.spell_ordinal_farsi(true) # => "دومین"
|
36
|
+
# 2054.spell_ordinal_farsi(true) # => "دو هزار و پنجاه چهارمین"
|
37
|
+
def spell_ordinal_farsi(*args)
|
38
|
+
if args[0]
|
39
|
+
exceptions = {0 => "صفر", 1 => "اولین", 3 => "سومین"}
|
40
|
+
suffix = "مین"
|
41
|
+
else
|
42
|
+
exceptions = {0 => "صفر", 1 => "اول", 3 => "سوم"}
|
43
|
+
suffix = "م"
|
44
|
+
end
|
45
|
+
|
46
|
+
make_ordinal_spell(exceptions, suffix)
|
47
|
+
end
|
48
|
+
|
49
|
+
private #---------------------------------------------------------
|
50
|
+
def spell(num_array)
|
51
|
+
# Dealing with signs
|
52
|
+
sign_m = num_array.include?("-") ? PERSIAN_DIGIT_SIGN[0] : ""
|
53
|
+
sign_p = num_array.include?("+") ? PERSIAN_DIGIT_SIGN[1] : ""
|
54
|
+
num_array.delete_at(num_array.index("-")) if sign_m.size > 0
|
55
|
+
num_array.delete_at(num_array.index("+")) if sign_p.size > 0
|
56
|
+
sign = sign_m + sign_p
|
57
|
+
|
58
|
+
zillion = 0
|
59
|
+
farsi_number = []
|
60
|
+
|
61
|
+
# Dealing with Zero
|
62
|
+
if (num_array.length == 1 && num_array[0] == "0" )
|
63
|
+
farsi_number = [PERSIAN_DIGIT_SPELL[0][10]]
|
64
|
+
num_array = []
|
65
|
+
end
|
66
|
+
|
67
|
+
while num_array.length > 0 do
|
68
|
+
spelling = []
|
69
|
+
num_array[0..2].each_with_index do |digit,index|
|
70
|
+
spelling[index] = PERSIAN_DIGIT_SPELL[index][digit.to_i]
|
71
|
+
if index == 1 && digit == "1" # Dealing with 10..19
|
72
|
+
spelling[1] = PERSIAN_DIGIT_SPELL["10..19"][num_array[0].to_i]
|
73
|
+
spelling[0] = nil
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
3.times { num_array.shift if num_array.length > 0 } # Eliminating the first 3 number of the array
|
78
|
+
dig = spelling.reverse.compact.join(PERSIAN_DIGIT_JOINT)
|
79
|
+
if dig.size > 0
|
80
|
+
dig << (" " + PERSIAN_DIGIT_SPELL["zillion"][zillion].to_s)
|
81
|
+
farsi_number.unshift(dig)
|
82
|
+
end
|
83
|
+
|
84
|
+
zillion += 1
|
85
|
+
end # End of While
|
86
|
+
|
87
|
+
sign + farsi_number.compact.join(PERSIAN_DIGIT_JOINT).strip
|
88
|
+
end
|
89
|
+
|
90
|
+
def make_ordinal_spell(exceptions, suffix)
|
91
|
+
if exceptions.include? @number
|
92
|
+
exceptions[@number]
|
93
|
+
else
|
94
|
+
(spell_farsi + suffix).gsub(/سه(م|مین)$/) { "سو#{$1}" }
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Convert
|
2
|
+
def to_farsi
|
3
|
+
FarsiFu::Convert.new(self).to_farsi
|
4
|
+
end
|
5
|
+
alias_method :to_persian, :to_farsi
|
6
|
+
|
7
|
+
def to_english
|
8
|
+
FarsiFu::Convert.new(self).to_english
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module NumToWord
|
13
|
+
def spell_farsi
|
14
|
+
FarsiFu::NumToWord.new(self).spell_farsi
|
15
|
+
end
|
16
|
+
|
17
|
+
def spell_ordinal_farsi(*args)
|
18
|
+
FarsiFu::NumToWord.new(self).spell_ordinal_farsi(args[0])
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
module WordToNum
|
23
|
+
def farsi_to_number
|
24
|
+
FarsiFu::WordToNum.new(self).to_number
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class String
|
29
|
+
include Convert
|
30
|
+
include WordToNum
|
31
|
+
end
|
32
|
+
|
33
|
+
class Numeric
|
34
|
+
include NumToWord
|
35
|
+
end
|
36
|
+
|
37
|
+
# Seems that Numeric works for both Float and Integers
|
38
|
+
# class Float
|
39
|
+
# include NumToWord
|
40
|
+
# end
|
data/lib/farsifu/version.rb
CHANGED
@@ -0,0 +1,66 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module FarsiFu
|
4
|
+
class WordToNum
|
5
|
+
|
6
|
+
def initialize(number_in_words)
|
7
|
+
@number_in_words = number_in_words
|
8
|
+
end
|
9
|
+
|
10
|
+
# It converts number represented in words to numeral.
|
11
|
+
# Example:
|
12
|
+
# "صد و بیست و یک".to_number #=> 121
|
13
|
+
def to_number
|
14
|
+
return @number_in_words if !(@number_in_words.is_a? String)
|
15
|
+
|
16
|
+
numbers_array = make_integer_array(@number_in_words)
|
17
|
+
|
18
|
+
memory = 0
|
19
|
+
answer = 0
|
20
|
+
reset = true
|
21
|
+
numbers_array.each do |number|
|
22
|
+
if reset || !(divisible_by_thousand? number)
|
23
|
+
reset = false
|
24
|
+
memory += number
|
25
|
+
else
|
26
|
+
memory *= number
|
27
|
+
answer += memory
|
28
|
+
memory = 0
|
29
|
+
reset = true
|
30
|
+
end
|
31
|
+
end
|
32
|
+
answer += memory
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
# returns an array of corresponding numbers from string
|
37
|
+
# [1, 1000000, 200, 30, 5, 1000, 400, 30, 3]
|
38
|
+
def make_integer_array(number_in_words)
|
39
|
+
number_in_words = eliminate_and(number_in_words.strip.squeeze(" ")).split(" ")
|
40
|
+
numbers_array = []
|
41
|
+
number_in_words.each do |number|
|
42
|
+
if power_of_ten? number
|
43
|
+
numbers_array << 10 ** POWER_OF_TEN[number]
|
44
|
+
else
|
45
|
+
numbers_array << EXCEPTIONS[number]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
numbers_array
|
49
|
+
end
|
50
|
+
|
51
|
+
# Removes "و" from the string
|
52
|
+
def eliminate_and(number_in_words)
|
53
|
+
number_in_words.gsub(/ و /, " ")
|
54
|
+
end
|
55
|
+
|
56
|
+
# Checkes if the number is power of divisible by thousand(bigger than 1000)
|
57
|
+
def divisible_by_thousand?(number)
|
58
|
+
number % 1000 == 0
|
59
|
+
end
|
60
|
+
|
61
|
+
# Checks if the number is power of ten
|
62
|
+
def power_of_ten? number
|
63
|
+
POWER_OF_TEN.keys.include? number
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|