rutils 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +5 -0
- data/README +104 -0
- data/TODO +26 -0
- data/bin/gilensize +8 -0
- data/lib/datetime/datetime.rb +61 -0
- data/lib/gilenson/gilenson.rb +280 -0
- data/lib/gilenson/gilenson_port.rb +332 -0
- data/lib/integration/blue_cloth_override.rb +8 -0
- data/lib/integration/integration.rb +24 -0
- data/lib/integration/rails_date_helper_override.rb +66 -0
- data/lib/integration/red_cloth_override.rb +17 -0
- data/lib/pluralizer/pluralizer.rb +208 -0
- data/lib/rutils.rb +14 -0
- data/lib/transliteration/transliteration.rb +173 -0
- data/test/run_tests.rb +4 -0
- data/test/t_datetime.rb +10 -0
- data/test/t_gilenson.rb +42 -0
- data/test/t_integration.rb +43 -0
- data/test/t_pluralize.rb +60 -0
- data/test/t_transliteration.rb +25 -0
- data/test/t_typografica.rb +57 -0
- metadata +73 -0
data/CHANGELOG
ADDED
data/README
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
== Добро пожаловать в RuTils
|
2
|
+
|
3
|
+
RuTils - простой обработчик русского текста, позволяющий использовать и обрабатывать
|
4
|
+
русский текст несколькими несложными способами. Основная цель RuTils - сделать
|
5
|
+
разработку русскоязычных приложений на Ruby (и Rails) максимально простой и приятной (в идеале - столь же
|
6
|
+
простой как и разработку оных на английском)
|
7
|
+
|
8
|
+
Весь функционал RuTils поддерживает только UTF-8 (настройка $KCODE / KanjiCode 'u'). Стандартно работа RuTils проверяется
|
9
|
+
как на стандартной версии Ruby, так и на парсере регулярных выражений Oniguruma (правда имейте в виду, что с ним
|
10
|
+
Gilenson работает медленнее).
|
11
|
+
|
12
|
+
|
13
|
+
Это версия RuTils
|
14
|
+
|
15
|
+
$Revision: 1.6 $
|
16
|
+
|
17
|
+
Пожалуйста упоминайте версию при сообщении ошибок.
|
18
|
+
|
19
|
+
Удостоверьтесь, что ваш скрипт правильно обрабатывает Unicode - то есть:
|
20
|
+
|
21
|
+
* Переменная $KCODE включена в режим 'u'
|
22
|
+
* В скрипт загружена библиотека jcode
|
23
|
+
|
24
|
+
Если вы используете RuTils для сайта под mod_ruby воспользуйтесь директивой RubyKanjiCode в своем httpd.conf.
|
25
|
+
|
26
|
+
== Cумма прописью
|
27
|
+
|
28
|
+
RuTils реализует сумму прописью для целых и дробных чисел, с дополнительным учетом рода. Например:
|
29
|
+
|
30
|
+
4.propisju => "четыре"
|
31
|
+
345.propisju => "триста сорок пять"
|
32
|
+
231.propisju(2) => "двести тридцать одна"
|
33
|
+
341.propisju_items(1, "чемодан", "чемодана", "чемоданов") => "триста сорок один чемодан"
|
34
|
+
(212.40).propisju_items(2, "сволочь", "сволочи", "сволочей") => "двести двенадцать целых четыре десятых сволочи"
|
35
|
+
|
36
|
+
Также реализуется выбор варианта числительного в зависимости от числа
|
37
|
+
|
38
|
+
15.items("кодер", "кодера", "кодеров") => "кодеров"
|
39
|
+
|
40
|
+
== Транслит
|
41
|
+
|
42
|
+
RuTils на данный момент реализует простейший транслит "в одну сторону".
|
43
|
+
|
44
|
+
"Вот такое вот дело".translify => "Vot takoye vot delo"
|
45
|
+
"Несомненный прогресс по сравнению с PHP".dirify => "nesomnennyi-progress-po-sravneniu-s-php"
|
46
|
+
|
47
|
+
В ближайшее время будет добавлен BiDi-транслит.
|
48
|
+
|
49
|
+
== Обработка русской типографики в HTML
|
50
|
+
|
51
|
+
RuTils включает Gilenson - порт Тыпографицы[http://pixel-apes.com/typografica] от
|
52
|
+
Pixel Apes на Ruby. Тыпографица - механизм автоматической расстановки подстановок в тексте
|
53
|
+
перед его выводом в HTML, оформляющий неразрывные пробелы, типографские кавычки
|
54
|
+
и реализующая элементарные макроподстановки.
|
55
|
+
|
56
|
+
Большое спасибо Роману Иванову aka Kukutz и Николаю Яремко aka Kuso Mendokuzee за изначальную реализацию
|
57
|
+
на PHP.
|
58
|
+
|
59
|
+
Имейте в виду, что на баги в Gilenson жаловаться разработчикам Typografica не стоит -
|
60
|
+
они вас не поймут и будут правы. Поддержку Gilenson PixelApes не осуществляют.
|
61
|
+
|
62
|
+
В комплекте также есть скрипт gilensize, которым можно поточно обрабатывать Unicode-тексты в среде UNIX
|
63
|
+
пользуясь стандартным выводом
|
64
|
+
|
65
|
+
$ cat myfile.txt | gilensize > myfile.html
|
66
|
+
|
67
|
+
== Интеграция с Rails, RedCloth и BlueCloth
|
68
|
+
|
69
|
+
RuTils в первую очередь задумывался как максимально "прозрачный" механизм обработки русского текста
|
70
|
+
в контексте Rails-приложения. Если вы используете RuTils в одном приложении с RedCloth или BlueCloth,
|
71
|
+
RuTils автоматически будет обрабатывать типографику во всех текстах, пропускаемых через них. Имейте в виду, что для
|
72
|
+
корректной работы этой функции RuTils надо загружать после модулей RedCloth и BlueCloth.
|
73
|
+
|
74
|
+
|
75
|
+
В принципе если вы пользуетесь RedCloth или BlueCloth все что ими обрабатывается будет автоматически
|
76
|
+
обрабатываться и Gilenson'ом тоже. В случае с RedCloth Glienson автоматически заменяет стандартные для
|
77
|
+
Textile английские кавычки и типографские знаки на свои - русские.
|
78
|
+
|
79
|
+
Перегрузку всех функций (RedCloth, BlueCloth и компоненты Rails) можно включать и отключать в любое время
|
80
|
+
с помощью метода overrides= модуля RuTils. Когда перегрузка выключена, все сторонние библиотеки будут работать
|
81
|
+
в стандартном режиме (например, RedCloth будет расставлять английские типографские кавычки).
|
82
|
+
|
83
|
+
== Требования
|
84
|
+
|
85
|
+
* Ruby 1.8.2, немного прямых рук.
|
86
|
+
* Rake[http://rake.rubyforge.org], Rails, RedCloth и BlueCloth для выполнения тестов
|
87
|
+
|
88
|
+
== Как использовать
|
89
|
+
|
90
|
+
Просто включите rutils в свою программу как gem
|
91
|
+
|
92
|
+
require_gem 'rutils'
|
93
|
+
|
94
|
+
или как библиотеку
|
95
|
+
|
96
|
+
require 'rutils'
|
97
|
+
|
98
|
+
== Где получить помощь
|
99
|
+
|
100
|
+
На странице проекта на RubyForge[http://rubyforge.org/projects/rutils]
|
101
|
+
|
102
|
+
== Работает ли это с текстом в кодировке Windows-1251
|
103
|
+
|
104
|
+
Нет и никогда не будет.
|
data/TODO
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
=TODO
|
2
|
+
|
3
|
+
==Gilenson
|
4
|
+
|
5
|
+
* Заменить все entities в Гиленсоне на UTF-эквиваленты (в том числе и в тестах)
|
6
|
+
(пока генерируемый им код содержит, например, raquo и nbsp - неприменимо для XML)
|
7
|
+
* Выяснить, стоит ли отрабатывать типографику в атрибутах тегов
|
8
|
+
* Полностью рефакторнуть (вынести каждую трансформацию в метод)
|
9
|
+
* чтобы тестить трансформации по одной
|
10
|
+
* чтобы применять трансформации по одной буде на то нужда
|
11
|
+
|
12
|
+
==Pluralization
|
13
|
+
|
14
|
+
* Истинная плюрализация без передачи рода и вариантов (как в Rails)
|
15
|
+
|
16
|
+
==Даты
|
17
|
+
|
18
|
+
* В принципе нужно обеспечить полноценное покрытие stfmt
|
19
|
+
|
20
|
+
==Rails
|
21
|
+
|
22
|
+
* distance_of_time_in_words и тому подобные
|
23
|
+
|
24
|
+
==Транслит
|
25
|
+
|
26
|
+
* bidi-транслит (Данил)
|
data/bin/gilensize
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
module RuTils
|
4
|
+
module DateTime
|
5
|
+
ABBR_MONTHNAMES = %w{ Янв Фев Мар Апр Май Июн Июл Авг Сен Окт Ноя Дек }
|
6
|
+
MONTHNAMES = %w{ Январь Февраль Март Апрель Май Июнь Июль Август Сентябрь Октябрь Ноябрь Декабрь }
|
7
|
+
def self.distance_of_time_in_words(from_time, to_time = 0, include_seconds = false, absolute = false) #nodoc
|
8
|
+
from_time = from_time.to_time if from_time.respond_to?(:to_time)
|
9
|
+
to_time = to_time.to_time if to_time.respond_to?(:to_time)
|
10
|
+
distance_in_minutes = (((to_time - from_time).abs)/60).round
|
11
|
+
distance_in_seconds = ((to_time - from_time).abs).round
|
12
|
+
|
13
|
+
case distance_in_minutes
|
14
|
+
when 0..1
|
15
|
+
return (distance_in_minutes==0) ? 'меньше минуты' : '1 минуту' unless include_seconds
|
16
|
+
|
17
|
+
case distance_in_seconds
|
18
|
+
when 0..5 then 'менее чем 5 секунд'
|
19
|
+
when 6..10 then 'менее чем 10 секунд'
|
20
|
+
when 11..20 then 'менее чем 20 секунд'
|
21
|
+
when 21..40 then 'пол-минуты'
|
22
|
+
when 41..59 then 'меньше минуты'
|
23
|
+
else '1 минуту'
|
24
|
+
end
|
25
|
+
|
26
|
+
when 2..45 then distance_in_minutes.propisju_items(2, "минута", "минуты", "минут")
|
27
|
+
when 46..90 then 'около часа'
|
28
|
+
when 90..1440 then "около " + (distance_in_minutes.to_f / 60.0).round.items("час", "часа", "часов")
|
29
|
+
when 1441..2880 then '1 день'
|
30
|
+
else (distance_in_minutes / 1440).round.items("день", "дня", "дней")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class RuTils::DateTime::RussianDate < Date
|
38
|
+
# Full month names, in English. Months count from 1 to 12; a
|
39
|
+
# month's numerical representation indexed into this array
|
40
|
+
# gives the name of that month (hence the first element is nil).
|
41
|
+
MONTHNAMES = [nil] + %w(Январь Февраль Март Апрель Май Июнь Июль
|
42
|
+
Август Сентябрь Октябрь Ноябрь Декабрь)
|
43
|
+
|
44
|
+
# Full names of days of the week, in English. Days of the week
|
45
|
+
# count from 0 to 6 (except in the commercial week); a day's numerical
|
46
|
+
# representation indexed into this array gives the name of that day.
|
47
|
+
DAYNAMES = %w(Воскресенье Понедельник Вторник Среда Четверг Пятница Суббота)
|
48
|
+
|
49
|
+
# Abbreviated month names, in English.
|
50
|
+
ABBR_MONTHNAMES = [nil] + %w(Янв Фев Мар Апр Май Июнь
|
51
|
+
Июль Авг Сен Окт Ноя Дек)
|
52
|
+
# Abbreviated day names, in English.
|
53
|
+
ABBR_DAYNAMES = %w(Вск Пн Вт Ср Чт Пт Сб)
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
class Date
|
58
|
+
def ru_strftime(*args)
|
59
|
+
RuTils::DateTime::RussianDate.new(self).strftime(*args)
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,280 @@
|
|
1
|
+
module RuTils
|
2
|
+
class Gilenson < String #:nodoc:
|
3
|
+
|
4
|
+
def initialize(*args)
|
5
|
+
# Задача (вкратце) состоит в том чтобы все ступени разработки развести в отдельные методы
|
6
|
+
# и тестировать их отдельно друг от друга (а также иметь возможность их по-одному включать и выключать).
|
7
|
+
# Фильтры, которые начинаются с lift работают с блоком (например - вытащить таги, провести обработку
|
8
|
+
# текста и вернуть все назад)
|
9
|
+
|
10
|
+
# Фильтры обрабатываются именно в таком порядке. Этот массив стравнивается с настройками, и если настройки
|
11
|
+
# для конкретного фильтра установлены в false этот фильтр обработан не будет.
|
12
|
+
# Каждый фильтр должен именоваться process_{filter}, принимать аргументом текст для обработки и возвращать его же!
|
13
|
+
# После того как фильтр включен в массив order_of_filters и для него написан метод фильтр по лумолчанию включается,
|
14
|
+
# и его настройку можно поменять с помощью аксессора с соотв. именем. Это делается автоматом.
|
15
|
+
# Главный обработчик должен сам понимать, использовать ли блок (если метод-делегат начинается с lift_)
|
16
|
+
# или просто process.
|
17
|
+
|
18
|
+
# Аксессор само собой генерируется автоматом.
|
19
|
+
|
20
|
+
@@order_of_filters = [
|
21
|
+
:inches,
|
22
|
+
:dashes,
|
23
|
+
:emdashes,
|
24
|
+
:specials,
|
25
|
+
:spacing,
|
26
|
+
:dashglue,
|
27
|
+
:nonbreakables,
|
28
|
+
:plusmin,
|
29
|
+
:degrees,
|
30
|
+
:phones,
|
31
|
+
:simple_quotes,
|
32
|
+
:typographer_quotes,
|
33
|
+
:compound_quotes,
|
34
|
+
]
|
35
|
+
|
36
|
+
# Символы, используемые в подстановках. Меняются через substitute_set(subst_name, subst_content)
|
37
|
+
# Нужно потому как ващето недопустим в XML, равно как и всякие mdash.
|
38
|
+
@@spec_chars = {
|
39
|
+
:laquo=>'«', #left acute
|
40
|
+
:raquo=>'»', #right acute
|
41
|
+
:ndash=>'–', #en dash
|
42
|
+
:mdash=>'—', #en dash
|
43
|
+
:inch=>'"', #en dash
|
44
|
+
}
|
45
|
+
|
46
|
+
@@phonemasks = [[ /([0-9]{4})\-([0-9]{2})\-([0-9]{2}) ([0-9]{2}):([0-9]{2}):([0-9]{2})/,
|
47
|
+
/([0-9]{4})\-([0-9]{2})\-([0-9]{2})/,
|
48
|
+
/(\([0-9\+\-]+\)) ?([0-9]{3})\-([0-9]{2})\-([0-9]{2})/,
|
49
|
+
/(\([0-9\+\-]+\)) ?([0-9]{2})\-([0-9]{2})\-([0-9]{2})/,
|
50
|
+
/(\([0-9\+\-]+\)) ?([0-9]{3})\-([0-9]{2})/,
|
51
|
+
/(\([0-9\+\-]+\)) ?([0-9]{2})\-([0-9]{3})/,
|
52
|
+
/([0-9]{3})\-([0-9]{2})\-([0-9]{2})/,
|
53
|
+
/([0-9]{2})\-([0-9]{2})\-([0-9]{2})/,
|
54
|
+
/([0-9]{1})\-([0-9]{2})\-([0-9]{2})/,
|
55
|
+
/([0-9]{2})\-([0-9]{3})/,
|
56
|
+
/([0-9]+)\-([0-9]+)/,
|
57
|
+
],[
|
58
|
+
'<nobr>\1–\2–\3 \4:\5:\6</nobr>',
|
59
|
+
'<nobr>\1–\2–\3</nobr>',
|
60
|
+
'<nobr>\1 \2–\3–\4</nobr>',
|
61
|
+
'<nobr>\1 \2–\3–\4</nobr>',
|
62
|
+
'<nobr>\1 \2–\3</nobr>',
|
63
|
+
'<nobr>\1 \2–\3</nobr>',
|
64
|
+
'<nobr>\1–\2–\3</nobr>',
|
65
|
+
'<nobr>\1–\2–\3</nobr>',
|
66
|
+
'<nobr>\1–\2–\3</nobr>',
|
67
|
+
'<nobr>\1–\2</nobr>',
|
68
|
+
'<nobr>\1–\2</nobr>'
|
69
|
+
]]
|
70
|
+
|
71
|
+
@@glueleft = ['рис.', 'табл.', 'см.', 'им.', 'ул.', 'пер.', 'кв.', 'офис', 'оф.', 'г.']
|
72
|
+
@@glueright = ['руб.', 'коп.', 'у.е.', 'мин.']
|
73
|
+
|
74
|
+
@@settings = {
|
75
|
+
"inches" => true, # преобразовывать дюймы в "
|
76
|
+
"laquo" => true, # кавычки-ёлочки
|
77
|
+
"farlaquo" => false, # кавычки-ёлочки для фара (знаки "больше-меньше")
|
78
|
+
"quotes" => true, # кавычки-английские лапки
|
79
|
+
"dash" => true, # короткое тире (150)
|
80
|
+
"emdash" => true, # длинное тире двумя минусами (151)
|
81
|
+
"(c)" => true,
|
82
|
+
"(r)" => true,
|
83
|
+
"(tm)" => true,
|
84
|
+
"(p)" => true,
|
85
|
+
"+-" => true, # спецсимволы, какие - понятно
|
86
|
+
"degrees" => true, # знак градуса
|
87
|
+
"<-->" => true, # отступы $Indent*
|
88
|
+
"dashglue" => true, "wordglue" => true, # приклеивание предлогов и дефисов
|
89
|
+
"spacing" => true, # запятые и пробелы, перестановка
|
90
|
+
"phones" => true, # обработка телефонов
|
91
|
+
"fixed" => false, # подгон под фиксированную ширину
|
92
|
+
"html" => false # запрет тагов html
|
93
|
+
}
|
94
|
+
# irrelevant - indentation with images
|
95
|
+
@@indent_a = "<!--indent-->"
|
96
|
+
@@indent_b = "<!--indent-->"
|
97
|
+
|
98
|
+
@@mark_tag = "\xF0\xF0\xF0\xF0" # Подстановочные маркеры тегов - BOM
|
99
|
+
@@mark_ignored = "\xFF\xFF\xFF\xFF" # Подстановочные маркеры неизменяемых групп - BOM+ =)
|
100
|
+
|
101
|
+
@@ignore = /notypo/ # regex, который игнорируется. Этим надо воспользоваться для обработки pre и code
|
102
|
+
|
103
|
+
self.methods.each do | m |
|
104
|
+
next unless m.include?("process_")
|
105
|
+
raise NoMethodError, "No hook for " + m unless @@order_of_filters.include?(m.gsub(/process_/, '').to_sym)
|
106
|
+
end
|
107
|
+
|
108
|
+
@@order_of_filters.each do |filter|
|
109
|
+
raise NoMethodError, "No process method for " + filter unless self.methods.include?("process_#{filter}".to_sym)
|
110
|
+
end
|
111
|
+
|
112
|
+
super(*args)
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
def to_html(*opts)
|
118
|
+
text = self.to_s.clone
|
119
|
+
lift_tags(text) do | text |
|
120
|
+
# lift_ignored(text) do |text|
|
121
|
+
for filter in @@order_of_filters
|
122
|
+
raise "UnknownFilter #process_#{filter} in filterlist!" unless self.respond_to?("process_#{filter}".to_sym)
|
123
|
+
self.send("process_#{filter}".to_sym, text) # if @settings[filter.to_sym] # вызываем конкретный фильтр
|
124
|
+
end
|
125
|
+
# end
|
126
|
+
end
|
127
|
+
text
|
128
|
+
end
|
129
|
+
|
130
|
+
# Вытаскивает теги из текста, выполняет переданный блок и возвращает теги на место.
|
131
|
+
# Теги в процессе заменяются на специальный маркер
|
132
|
+
def lift_tags(text, marker="\xF0\xF0\xF0\xF0", &block)
|
133
|
+
|
134
|
+
# Выцепляем таги
|
135
|
+
# re = /<\/?[a-z0-9]+("+ # имя тага
|
136
|
+
# "\s+("+ # повторяющая конструкция: хотя бы один разделитель и тельце
|
137
|
+
# "[a-z]+("+ # атрибут из букв, за которым может стоять знак равенства и потом
|
138
|
+
# "=((\'[^\']*\')|(\"[^\"]*\")|([0-9@\-_a-z:\/?&=\.]+))"+ #
|
139
|
+
# ")?"+
|
140
|
+
# ")?"+
|
141
|
+
# ")*\/?>|\xA2\xA2[^\n]*?==/i;
|
142
|
+
|
143
|
+
re = /(<\/?[a-z0-9]+(\s+([a-z]+(=((\'[^\']*\')|(\"[^\"]*\")|([0-9@\-_a-z:\/?&=\.]+)))?)?)*\/?>)/ui
|
144
|
+
|
145
|
+
tags = text.scan(re).inject([]) { | ar, match | ar << match[0] }
|
146
|
+
text.gsub!(re, "\xF0\xF0\xF0\xF0") #маркер тега
|
147
|
+
|
148
|
+
yield(text, marker) if block_given? #делаем все что надо сделать без тегов
|
149
|
+
|
150
|
+
tags.each { | tag | text.sub!(marker, tag) } # Вставляем таги обратно.
|
151
|
+
|
152
|
+
end
|
153
|
+
|
154
|
+
# Выцепляет игнорированные символы, выполняет блок с текстом
|
155
|
+
# без этих символов а затем вставляет их на место
|
156
|
+
def lift_ignored(text, marker = "\xFF\xFF\xFF\xFF", &block)
|
157
|
+
ignored = text.scan(@ignore)
|
158
|
+
text.gsub!(@ignore, marker)
|
159
|
+
|
160
|
+
# обрабатываем текст
|
161
|
+
yield(text, marker) if block_given?
|
162
|
+
|
163
|
+
# возвращаем игнорированные символы
|
164
|
+
ignored.each { | tag | text.sub!(marker, tag) }
|
165
|
+
end
|
166
|
+
|
167
|
+
# Кавычки - лапки
|
168
|
+
def process_simple_quotes(text)
|
169
|
+
text.gsub!( /\"\"/ui, """")
|
170
|
+
text.gsub!( /\"\.\"/ui, ""."")
|
171
|
+
_text = '""';
|
172
|
+
while _text != text do
|
173
|
+
_text = text
|
174
|
+
text.gsub!( /(^|\s|\xFF\xFF\xFF\xFF|\xF0\xF0\xF0\xF0|>)\"([0-9A-Za-z\'\!\s\.\?\,\-\&\;\:\_\xF0\xF0\xF0\xF0\xFF\xFF\xFF\xFF]+(\"|”))/ui, '\1“\2')
|
175
|
+
#this doesnt work in-place. somehow.
|
176
|
+
text.replace text.gsub( /(\&\#147\;([A-Za-z0-9\'\!\s\.\?\,\-\&\;\:\xF0\xF0\xF0\xF0\xFF\xFF\xFF\xFF\_]*).*[A-Za-z0-9][\xF0\xF0\xF0\xF0\xFF\xFF\xFF\xFF\?\.\!\,]*)\"/ui, '\1”')
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
# Кавычки - елочки
|
181
|
+
def process_typographer_quotes(text)
|
182
|
+
# 2. ёлочки
|
183
|
+
text.gsub!( /\"\"/ui, """");
|
184
|
+
text.gsub!( /(^|\s|\xFF\xFF\xFF\xFF|\xF0\xF0\xF0\xF0|>|\()\"((\xFF\xFF\xFF\xFF|\xF0\xF0\xF0\xF0)*[~0-9ёЁA-Za-zА-Яа-я\-:\/\.])/ui, "\\1«\\2");
|
185
|
+
# nb: wacko only regexp follows:
|
186
|
+
text.gsub!( /(^|\s|\xFF\xFF\xFF\xFF|\xF0\xF0\xF0\xF0|>|\()\"((\xFF\xFF\xFF\xFF|\xF0\xF0\xF0\xF0|\/ |\/|\!)*[~0-9ёЁA-Za-zА-Яа-я\-:\/\.])/ui, "\\1«\\2")
|
187
|
+
_text = "\"\"";
|
188
|
+
while (_text != text) do
|
189
|
+
_text = text;
|
190
|
+
text.gsub!( /(\«\;([^\"]*)[ёЁA-Za-zА-Яа-я0-9\.\-:\/](\xFF\xFF\xFF\xFF|\xF0\xF0\xF0\xF0)*)\"/sui, "\\1»")
|
191
|
+
# nb: wacko only regexps follows:
|
192
|
+
text.gsub!( /(\«\;([^\"]*)[ёЁA-Za-zА-Яа-я0-9\.\-:\/](\xFF\xFF\xFF\xFF|\xF0\xF0\xF0\xF0)*\?(\xFF\xFF\xFF\xFF|\xF0\xF0\xF0\xF0)*)\"/sui, "\\1»")
|
193
|
+
text.gsub!( /(\«\;([^\"]*)[ёЁA-Za-zА-Яа-я0-9\.\-:\/](\xFF\xFF\xFF\xFF|\xF0\xF0\xF0\xF0|\/|\!)*)\"/sui, "\\1»")
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
# Cложные кавычки
|
198
|
+
def process_compound_quotes(text)
|
199
|
+
text.gsub!(/(\&\#147\;(([A-Za-z0-9'!\.?,\-&;:]|\s|\xF0\xF0\xF0\xF0|\xFF\xFF\xFF\xFF)*)«(.*)»)»/ui,"\\1”");
|
200
|
+
end
|
201
|
+
|
202
|
+
# Обрабатывает короткое тире
|
203
|
+
def process_dashes(text)
|
204
|
+
text.gsub!( /(\s|;)\-(\s)/ui, "\\1–\\2")
|
205
|
+
end
|
206
|
+
|
207
|
+
# Обрабатывает длинные тире
|
208
|
+
def process_emdashes(text)
|
209
|
+
text.gsub!( /(\s|;)\-\-(\s)/ui, "\\1—\\2")
|
210
|
+
end
|
211
|
+
|
212
|
+
# Обрабатывает знаки копирайта, торговой марки и т.д.
|
213
|
+
def process_specials(text)
|
214
|
+
# 4. (с)
|
215
|
+
text.gsub!(/\([сСcC]\)((?=\w)|(?=\s[0-9]+))/u, "©")
|
216
|
+
# 4a. (r)
|
217
|
+
text.gsub!( /\(r\)/ui, "<sup>®</sup>")
|
218
|
+
|
219
|
+
# 4b. (tm)
|
220
|
+
text.gsub!( /\(tm\)|\(тм\)/ui, "™")
|
221
|
+
# 4c. (p)
|
222
|
+
text.gsub!( /\(p\)/ui, "§")
|
223
|
+
end
|
224
|
+
|
225
|
+
# Склейка дефисоов
|
226
|
+
def process_dashglue(text)
|
227
|
+
text.gsub!( /([a-zа-яА-Я0-9]+(\-[a-zа-яА-Я0-9]+)+)/ui, '<nobr>\1</nobr>')
|
228
|
+
end
|
229
|
+
|
230
|
+
# Запятые и пробелы
|
231
|
+
def process_spacing(text)
|
232
|
+
text.gsub!( /(\s*)([,]*)/sui, "\\2\\1");
|
233
|
+
text.gsub!( /(\s*)([\.?!]*)(\s*[ЁА-ЯA-Z])/su, "\\2\\1\\3");
|
234
|
+
end
|
235
|
+
|
236
|
+
# Неразрывные пробелы - пока глючит страшным образом
|
237
|
+
def process_nonbreakables(text)
|
238
|
+
text.replace " " + text + " ";
|
239
|
+
_text = " " + text + " ";
|
240
|
+
until _text == text
|
241
|
+
_text.replace text.clone
|
242
|
+
text.gsub!( /(\s+)([a-zа-яА-Я]{1,2})(\s+)([^\\s$])/ui, '\1\2 \4')
|
243
|
+
text.gsub!( /(\s+)([a-zа-яА-Я]{3})(\s+)([^\\s$])/ui, '\1\2 \4')
|
244
|
+
end
|
245
|
+
|
246
|
+
for i in @glueleft
|
247
|
+
text.gsub!( /(\s)(#{i})(\s+)/sui, '\1\2 ')
|
248
|
+
end
|
249
|
+
|
250
|
+
for i in @glueright
|
251
|
+
text.gsub!( /(\s)(#{i})(\s+)/sui, ' \2\3')
|
252
|
+
end
|
253
|
+
|
254
|
+
end
|
255
|
+
|
256
|
+
# Знак дюйма
|
257
|
+
def process_inches(text)
|
258
|
+
text.gsub!(/\s([0-9]{1,2}([\.,][0-9]{1,2})?)\"/ui, ' \1"') if @settings["inches"]
|
259
|
+
end
|
260
|
+
|
261
|
+
# Обрабатывает знак +/-
|
262
|
+
def process_plusmin(text)
|
263
|
+
text.gsub!(/\+\-/ui, "±") if @settings["+-"]
|
264
|
+
end
|
265
|
+
|
266
|
+
# Обрабатывает телефоны
|
267
|
+
def process_phones(text)
|
268
|
+
@phonemasks[0].each_with_index do |regex, i|
|
269
|
+
text.gsub!(regex, @phonemasks[1][i])
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
# Обрабатывает знак градуса, набранный как caret
|
274
|
+
def process_degrees(text)
|
275
|
+
text.gsub!( /-([0-9])+\^([FCС])/, '–\1°\2')
|
276
|
+
text.gsub!( /\+([0-9])+\^([FCС])/, "+\\1°\\2")
|
277
|
+
text.gsub!( /\^([FCС])/, "°\\1")
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|