farsifu 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|