rutils 0.0.3
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/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
|