typograph 0.0.1.pre.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +46 -0
- data/Rakefile +21 -0
- data/lib/typograph/adapter.rb +26 -0
- data/lib/typograph/adapters/russian.rb +267 -0
- data/lib/typograph/processor.rb +55 -0
- data/lib/typograph/version.rb +3 -0
- data/lib/typograph.rb +10 -0
- data/spec/data/_test.dr_death.dat +2 -0
- data/spec/data/_test.fazeful.dat +2 -0
- data/spec/data/_test.isaykin.dat +50 -0
- data/spec/data/_test.typo-basic.dat +227 -0
- data/spec/data/_test.typo-dizzyman.dat +35 -0
- data/spec/data/_test.typo-html.dat +72 -0
- data/spec/data/_test.typo-latest.dat +290 -0
- data/spec/data/_test.typo-not_used.dat +2 -0
- data/spec/data/_test.typo-phones.dat +14 -0
- data/spec/data/_test.typo-quotes.dat +35 -0
- data/spec/data/_test.typo-symbols.dat +83 -0
- data/spec/data/_test.typo-unix.dat +2 -0
- data/spec/typograph_spec.rb +39 -0
- data/spec/xml/core.xml +107 -0
- data/spec/xml/russian.xml +1066 -0
- data/typograph.gemspec +26 -0
- metadata +154 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 sterebooster
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# Typograph
|
2
|
+
|
3
|
+
Gem for typographing russian texts. Ruby port of [SamDark's Typograph](https://github.com/samdark/Typograph).
|
4
|
+
|
5
|
+
## TODO
|
6
|
+
- implement best opensource russian typograph as ruby gem
|
7
|
+
- Port [Typograph](https://github.com/samdark/Typograph) (one of the best opensource russain typographs)
|
8
|
+
- add to [multi_typograf](https://github.com/stereobooster/multi_typograf)
|
9
|
+
- implement english typograph
|
10
|
+
- implement typograph for other languages. Implement settings throught YAML
|
11
|
+
- [web typography 6](http://habrahabr.ru/post/25958/)
|
12
|
+
- [foreign typography](http://habrahabr.ru/post/117142/)
|
13
|
+
- [deutch](http://habrahabr.ru/post/12742/)
|
14
|
+
- http://de.wikipedia.org/wiki/Geviertstrich
|
15
|
+
- http://de.wikipedia.org/wiki/Typografie_für_HTML
|
16
|
+
|
17
|
+
## Alternatives
|
18
|
+
|
19
|
+
### ruby gems, wrappers for online services - russian
|
20
|
+
- [art_typograf](https://github.com/stereobooster/art_typograf) wrapper for http://www.artlebedev.ru/tools/typograf/
|
21
|
+
- [typograf](https://github.com/stereobooster/typograf) wrapper for http://www.typograf.ru/
|
22
|
+
|
23
|
+
### ruby gems - russian
|
24
|
+
- [typographer](https://github.com/brain-geek/typographer)
|
25
|
+
- [typography](https://github.com/antonversal/typography)
|
26
|
+
- [typographica](https://github.com/akolosov/typographica)
|
27
|
+
|
28
|
+
### ruby - english
|
29
|
+
- [SmartyPants](http://rubydoc.info/gems/redcarpet/2.1.1/Redcarpet/Render/SmartyPants)
|
30
|
+
- [rubypants](https://github.com/jmcnevin/rubypants)
|
31
|
+
|
32
|
+
### other
|
33
|
+
- [habari-typography](https://github.com/ahutchings/habari-typography)
|
34
|
+
- [typography-helper](https://github.com/hunter/typography-helper) english
|
35
|
+
|
36
|
+
## Usage
|
37
|
+
|
38
|
+
TODO: Write usage instructions here
|
39
|
+
|
40
|
+
## Contributing
|
41
|
+
|
42
|
+
1. Fork it
|
43
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
44
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
45
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
46
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
desc "Run all specs"
|
5
|
+
RSpec::Core::RakeTask.new(:spec)
|
6
|
+
|
7
|
+
task :default => :spec
|
8
|
+
|
9
|
+
LANG = "ru_RU.UTF-8"
|
10
|
+
|
11
|
+
SET_CMD = case RUBY_PLATFORM
|
12
|
+
when /mingw32/ then
|
13
|
+
"set"
|
14
|
+
else
|
15
|
+
"export"
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "run tests"
|
19
|
+
task :test do
|
20
|
+
sh "#{SET_CMD} LANG=#{LANG} && chcp 65001 && bundle exec rake"
|
21
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'htmlentities'
|
4
|
+
|
5
|
+
module Typograph
|
6
|
+
class Adapter
|
7
|
+
def initialize(options={})
|
8
|
+
@options = options
|
9
|
+
end
|
10
|
+
|
11
|
+
def process(text)
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
# Приводим символы в строке к единой форме для последующей обработки
|
16
|
+
def normalize(str)
|
17
|
+
# Убираем неразрывные пробелы
|
18
|
+
str.gsub!(/ | /, ' ')
|
19
|
+
# Приводим кавычки к «"»
|
20
|
+
str.gsub!(/(„|“|")/, '"')
|
21
|
+
#
|
22
|
+
str.gsub!(/^\s+|\s+$/, '')
|
23
|
+
HTMLEntities.new.decode(str)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,267 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Typograph
|
4
|
+
module Adapters
|
5
|
+
class Russian < Adapter
|
6
|
+
def initialize(options={})
|
7
|
+
@options = options
|
8
|
+
|
9
|
+
abbr = 'ООО|ОАО|ЗАО|ЧП|ИП|НПФ|НИИ|ООО\p{Zs}ТПК'
|
10
|
+
prepos = 'а|в|во|вне|и|или|к|о|с|у|со|об|обо|от|ото|то|на|не|ни|но|из|изо|за|уж|на|по|под|подо|пред|предо|про|над|надо|как|без|безо|что|да|для|до|там|ещё|их|ко|меж|между|перед|передо|около|через|сквозь|для|при|я'
|
11
|
+
metrics = 'мм|см|м|км|г|кг|б|кб|мб|гб|dpi|px'
|
12
|
+
shortages = 'г|гр|тов|пос|c|ул|д|пер|м|зам|см'
|
13
|
+
money = 'руб\.|долл\.|евро|у\.е\.'
|
14
|
+
countables = 'млн|тыс'
|
15
|
+
|
16
|
+
@rules_strict = {
|
17
|
+
# Много пробелов или табуляций -> один пробел
|
18
|
+
/( |\t)+/ => ' ',
|
19
|
+
# Запятые после «а» и «но». Если уже есть — не ставим.
|
20
|
+
/([^,])\s(а|но)\s/ => '\1, \2 ',
|
21
|
+
}
|
22
|
+
|
23
|
+
@rules_symbols = {
|
24
|
+
# Лишние знаки.
|
25
|
+
# TODO: сделать красиво
|
26
|
+
/([^!])!!([^!])/ => '\1!\2',
|
27
|
+
/([^?])\?\?([^?])/ => '\1?\2',
|
28
|
+
/(\p{L})\s*\.\.(\p{Zs})/ => '\1.\2', # new
|
29
|
+
/(\p{L});[;\s]*(;)/ => '\1;', # new
|
30
|
+
/(\p{L}),[,\s]*(,)/ => '\1,', # new
|
31
|
+
/(\p{L}):[:\s]*(:)/ => '\1:', # new
|
32
|
+
|
33
|
+
/([!\?])\s*(!\s*)[!\s]*(!)/ => '\1!!', # new
|
34
|
+
/(\?\s*)(\?\s*)[\?\s]*(\?)/ => '???', # new
|
35
|
+
/(\.\s*)(\.\s*)[\.\s]*(\.)/ => '...', # new
|
36
|
+
/(,\s*)[,\s]*(,)/ => ',', # new
|
37
|
+
/;{2,}/ => ';', # new
|
38
|
+
/,{2,}/ => ',', # new
|
39
|
+
/:{2,}/ => ':', # new
|
40
|
+
|
41
|
+
# /([;,:])(\S)/ => '\1 \2', # new
|
42
|
+
|
43
|
+
# Занятная комбинация
|
44
|
+
/!\?/ => '?!',
|
45
|
+
|
46
|
+
# Знаки (c), (r), (tm)
|
47
|
+
/\((c|с)\)/i => '©',
|
48
|
+
/\(r\)/i => '<sup><small>®</small></sup>',
|
49
|
+
/\(tm\)/i => '<sup>™</sup>',
|
50
|
+
|
51
|
+
# От 2 до 5 знака точки подряд - на знак многоточия (больше - мб авторской задумкой).
|
52
|
+
/\s*\.{2,5}/ => '…',
|
53
|
+
|
54
|
+
# Дроби
|
55
|
+
# TODO: найти замену \b
|
56
|
+
/\b1\/2\b/ => '½',
|
57
|
+
/\b1\/3\b/ => '⅓',
|
58
|
+
/\b1\/4\b/ => '¼',
|
59
|
+
/\b3\/4\b/ => '¾',
|
60
|
+
|
61
|
+
# LО'Лайт, O'Reilly
|
62
|
+
/([a-zA-Z])'([а-яА-Яa-zA-Z])/i => '\1’\2',
|
63
|
+
|
64
|
+
/'/ => ''', # str_replace?
|
65
|
+
|
66
|
+
# Размеры 10x10, правильный знак + убираем лишние пробелы
|
67
|
+
/(\p{Nd}+)\p{Zs}{0,}?[x|X|х|Х|*]\p{Zs}{0,}(\p{Nd}+)/ => '\1×\2',
|
68
|
+
|
69
|
+
# +-
|
70
|
+
/([^\+]|^)\+-/ => '\1±',
|
71
|
+
|
72
|
+
# Стрелки
|
73
|
+
/([^-]|^)->/ => '\1→',
|
74
|
+
/<-([^-]|$)/ => '←\1'
|
75
|
+
}
|
76
|
+
|
77
|
+
@rules_quotes = {
|
78
|
+
# Разносим неправильные кавычки
|
79
|
+
/([^"]\p{L}+)"(\p{L}+)"/ => '\1 "\2"',
|
80
|
+
/"(\p{L}+)"(\p{L}+)/ => '"\1" \2',
|
81
|
+
|
82
|
+
# Превращаем кавычки в ёлочки.
|
83
|
+
/(\P{L})?"([^"]*)"(\P{L})?/ => '\1«\2»\3'
|
84
|
+
}
|
85
|
+
|
86
|
+
@rules_braces = {
|
87
|
+
# Оторвать скобку от слова
|
88
|
+
/(\p{L})\(/ => '\1 (',
|
89
|
+
# Слепляем скобки со словами
|
90
|
+
/\( /m => '(',
|
91
|
+
/ \)/m => ')'
|
92
|
+
}
|
93
|
+
|
94
|
+
@rules_main = {
|
95
|
+
# Конфликт с «газо- и электросварка»
|
96
|
+
# Оторвать тире от слова
|
97
|
+
# /(\p{L})- / => '\1 - ',
|
98
|
+
|
99
|
+
# Знаки с предшествующим пробелом… нехорошо!
|
100
|
+
/(\p{L}|>|\p{Nd}) +([?!:,;]|…)/ => '\1\2',
|
101
|
+
/([?!:,;])(\p{L}|<)/ => '\1 \2',
|
102
|
+
# Для точки отдельно
|
103
|
+
/(\p{L})\p{Zs}(?:\.)(\p{Zs}|$)/ => '\1.\2',
|
104
|
+
# Но перед кавычками пробелов не ставим
|
105
|
+
/([?!:,;\.])\p{Zs}(»)/ => '\1\2',
|
106
|
+
|
107
|
+
# Неразрывные названия организаций и абревиатуры форм собственности
|
108
|
+
# ~ почему не один ?
|
109
|
+
# ! названия организаций тоже могут содержать пробел !
|
110
|
+
/(#{abbr})\p{Zs}+(«[^»]*»)/ => '<nobr>\1 \2</nobr>',
|
111
|
+
|
112
|
+
# Нельзя отрывать сокращение от относящегося к нему слова.
|
113
|
+
# Например: тов. Сталин, г. Воронеж
|
114
|
+
# Ставит пробел, если его нет.
|
115
|
+
/(^|[^a-zA-Zа-яА-Я])(#{shortages})\.\s?([А-Я0-9]+)/m => '\1\2. \3',
|
116
|
+
|
117
|
+
# Не отделять стр., с. и т.д. от номера.
|
118
|
+
/(стр|с|табл|рис|илл)\.\p{Zs}*(\p{Nd}+)~/mi => '\1. \2',
|
119
|
+
|
120
|
+
# Не разделять 2007 г., ставить пробел, если его нет. Ставит точку, если её нет.
|
121
|
+
/({Nd}+)\p{Zs}*([гГ])\.\s/m => '\1 \2. ',
|
122
|
+
|
123
|
+
# Неразрывный пробел между цифрой и единицей измерения
|
124
|
+
/(\p{Nd}+)\s*(#{metrics})/m => '\1 \2',
|
125
|
+
|
126
|
+
# Сантиметр и другие ед. измерения в квадрате, кубе и т.д.
|
127
|
+
/(\p{Zs}#{metrics})(\p{Nd}+)/ => '\1<sup>\2</sup>',
|
128
|
+
|
129
|
+
# Знак дефиса или два знака дефиса подряд — на знак длинного тире.
|
130
|
+
# + Нельзя разрывать строку перед тире, например: Знание — сила, Курить — здоровью вредить.
|
131
|
+
/\p{Zs}+(?:--?|—)(?=\p{Zs})/ => ' —',
|
132
|
+
/^(?:--?|—)(?=\p{Zs})/ => '—',
|
133
|
+
|
134
|
+
# Прямая речь
|
135
|
+
/(?:^|\s+)(?:--?|—)(?=\p{Zs})/ => "—",
|
136
|
+
|
137
|
+
# Знак дефиса, ограниченный с обоих сторон цифрами — на знак короткого тире.
|
138
|
+
/(?<=\p{Nd})-(?=\p{Nd})/ => '–',
|
139
|
+
|
140
|
+
# Знак дефиса, ограниченный с обоих сторон пробелами — на знак длинного тире.
|
141
|
+
/(\s)(&ndash|–)(\s)/ => ' — ',
|
142
|
+
|
143
|
+
# Знак дефиса, идущий после тэга и справа пробел — на знак длинного тире.
|
144
|
+
/(?<=>)(&ndash|–|-)(\s)/ => '— ',
|
145
|
+
|
146
|
+
# Расстановка дефисов перед -ка, -де, -кась
|
147
|
+
/\b(\S+)\s(ка|де|кась)\b/i => '<nobr>\1-\2</nobr>',
|
148
|
+
|
149
|
+
# Расстановка дефиса после кое-, кой-
|
150
|
+
/\b(кое|кой)[\s-](как|кого|какой)\b/i => '<nobr>\1-\2</nobr>',
|
151
|
+
|
152
|
+
# Расстановка дефисов перед «-либо», «-нибудь».
|
153
|
+
/(кто|что|где|когда|почему|зачем|кем|чем)[\s-]?(либо|нибудь|то)/i => '<nobr>\1–\2</nobr>',
|
154
|
+
|
155
|
+
# Расстановка дефисов в предлогах «из-за», «из-под», «по-над», «по-под».
|
156
|
+
/\b(из)[\s-]?(за|под)\b/i => '<nobr>\1–\2</nobr>',
|
157
|
+
/\b(по)[\s-]?(над|под)\b/i => '<nobr>\1–\2</nobr>',
|
158
|
+
|
159
|
+
# Нельзя оставлять в конце строки предлоги и союзы
|
160
|
+
/(?<=\p{Zs}|^|\P{L})(#{prepos})(\s+)/i => '\1 ',
|
161
|
+
|
162
|
+
# Нельзя отрывать частицы бы, ли, же от предшествующего слова, например: как бы, вряд ли, так же.
|
163
|
+
# /(?<=[^\p{Zs}])(\p{Zs}+)(ж|бы|б|же|ли|ль|либо|или)(?=<.*?>*[\p{Zs})!?.])/i => ' \2',
|
164
|
+
/(?<=\S)(\s+)(ж|бы|б|же|ли|ль|либо|или)(?=(<.*?>)*[\p{Zs})!?.…])/i => ' \2',
|
165
|
+
|
166
|
+
# Неразрывный пробел после инициалов.
|
167
|
+
/([А-ЯA-Z]\.)\s?([А-ЯA-Z]\.)\p{Zs}?([А-Яа-яA-Za-z]+)/m => '\1\2 \3',
|
168
|
+
|
169
|
+
# Сокращения сумм не отделяются от чисел.
|
170
|
+
/(\p{Nd}+)\p{Zs}?(#{countables})/m => '\1 \2',
|
171
|
+
|
172
|
+
# «уе» в денежных суммах
|
173
|
+
/(\p{Nd}+|#{countables})\p{Zs}?уе/m => '\1 у.е.',
|
174
|
+
|
175
|
+
# Денежные суммы, расставляя пробелы в нужных местах.
|
176
|
+
/(\p{Nd}+|#{countables})\p{Zs}?(#{money})/m => '\1 \2',
|
177
|
+
|
178
|
+
# Неразрывные пробелы в кавычках
|
179
|
+
# "/($sym[lquote]\S*)(\s+)(\S*$sym[rquote])/U" => '\1'.\sym["nbsp"].'\3',
|
180
|
+
|
181
|
+
# Телефоны
|
182
|
+
/(?:тел\.?\/?факс:?\s?\((\d+)\))/i => 'тел./факс: (\1)',
|
183
|
+
|
184
|
+
/тел[:\.] ?(\p{Nd}+)/m => '<nobr>тел: \1</nobr>',
|
185
|
+
|
186
|
+
# Номер версии программы пишем неразрывно с буковкой v.
|
187
|
+
/([vв]\.) ?(\p{Nd})/i => '\1 \2',
|
188
|
+
/(\p{L}) ([vв]\.)/i => '\1 \2',
|
189
|
+
|
190
|
+
# % не отделяется от числа
|
191
|
+
/(\p{Nd}+)\p{Zs}+%/ => '\1%',
|
192
|
+
|
193
|
+
# IP-адреса рвать нехорошо
|
194
|
+
/(1\p{Nd}{0,2}|2(\p{Nd}|[0-5]\p{Nd}+)?)\.(0|1\p{Nd}{0,2}|2(\p{Nd}|[0-5]\p{Nd})?)\.(0|1\p{Nd}{0,2}|2(\p{Nd}|[0-5]\p{Nd})?)\.(0|1\p{Nd}{0,2}|2(\p{Nd}|[0-5]\p{Nd})?)/ =>
|
195
|
+
'<nobr>\0</nobr>'
|
196
|
+
}
|
197
|
+
end
|
198
|
+
|
199
|
+
def apply_rules(rules, str)
|
200
|
+
res = str.dup
|
201
|
+
rules.each do |rul, rep|
|
202
|
+
str.gsub!(rul, rep)
|
203
|
+
end
|
204
|
+
str
|
205
|
+
end
|
206
|
+
|
207
|
+
def process(str)
|
208
|
+
# str = apply_rules(rules_quotes, str) <------- DON'T WORK PROP!!!
|
209
|
+
str = apply_rules(@rules_strict, str) # Сначала применим строгие правила: пробелы, запятые
|
210
|
+
str = quotes(str) # правильно расставим кавычки
|
211
|
+
str = apply_rules(@rules_main, str)
|
212
|
+
str = apply_rules(@rules_symbols, str)
|
213
|
+
str = apply_rules(@rules_braces, str)
|
214
|
+
end
|
215
|
+
|
216
|
+
def quotes(text)
|
217
|
+
quot11='«'
|
218
|
+
quot12='»'
|
219
|
+
quot21='«'
|
220
|
+
quot22='»'
|
221
|
+
# „“
|
222
|
+
|
223
|
+
quotes = ['"','«','»','«','»','«','»','“','„','„','“','„','“','”','‘','’']
|
224
|
+
quotes = Regexp.new quotes.join('|')
|
225
|
+
text.gsub!(quotes, '"') # Единый тип кавычек
|
226
|
+
text.gsub!('""', '"')
|
227
|
+
|
228
|
+
text.gsub!(/"(\P{L})/, '»\1') # Взято из старой реализации
|
229
|
+
text.gsub!(/(\P{L})"/, '\1«') # Взято из старой реализации
|
230
|
+
|
231
|
+
# text.gsub!(/([^=]|\A)""(\.{2,4}[а-яА-Я\w\-]+|[а-яА-Я\w\-]+)/, '\1<typo:quot1>"\2') # Двойных кавычек уже нет
|
232
|
+
text.gsub!(/([^=]|\A)"(\.{2,4}[\p{L}\p{M}]+|[\p{L}\p{M}\-]+)/, '\1<typo:quot1>\2')
|
233
|
+
# text.gsub!(/([а-яА-Я\w\.\-]+)""([\n\.\?\!, \)][^>]{0,1})/, '\1"</typo:quot1>\2') # Двойных кавычек уже нет
|
234
|
+
text.gsub!(/([\p{L}\p{M}\.\-]+)"([\n\.\?\!, \)][^>]{0,1})/, '\1</typo:quot1>\2')
|
235
|
+
text.gsub!(/(<\/typo:quot1>[\.\?\!]{1,3})"([\n\.\?\!, \)][^>]{0,1})/, '\1</typo:quot1>\2')
|
236
|
+
text.gsub!(/(<typo:quot1>[\p{L}\p{M}\.\- \n]*?)<typo:quot1>(.+?)<\/typo:quot1>/, '\1<typo:quot2>\2</typo:quot2>')
|
237
|
+
text.gsub!(/(<\/typo:quot2>.+?)<typo:quot1>(.+?)<\/typo:quot1>/, '\1<typo:quot2>\2</typo:quot2>')
|
238
|
+
text.gsub!(/(<typo:quot2>.+?<\/typo:quot2>)\.(.+?<typo:quot1>)/, '\1</typo:quot1>.\2')
|
239
|
+
text.gsub!(/(<typo:quot2>.+?<\/typo:quot2>)\.(?!<\/typo:quot1>)/, '\1</typo:quot1>.\2\3\4')
|
240
|
+
# text.gsub!(/""/, '</typo:quot2></typo:quot1>') # Двойных кавычек уже нет
|
241
|
+
text.gsub!(/(?<=<typo:quot1>)(.+?)<typo:quot2>(.+?)(?!<\/typo:quot2>)/, '\1<typo:quot2>\2')
|
242
|
+
# text.gsub!(/"/, '<typo:quot1>') # Непонятный хак
|
243
|
+
# text.gsub!(/(<[^>]+)<\/typo:quot\d>/, '\1"') # Еще более непонятный хак
|
244
|
+
|
245
|
+
text.gsub!(/"$/, '</typo:quot2>') # new
|
246
|
+
|
247
|
+
text.gsub!('<typo:quot1>', quot11)
|
248
|
+
text.gsub!('</typo:quot1>', quot12)
|
249
|
+
text.gsub!('<typo:quot2>', quot21)
|
250
|
+
text.gsub!('</typo:quot2>', quot22)
|
251
|
+
|
252
|
+
text.gsub!(/(^|\s)»(<)/, '\1«\2') # new
|
253
|
+
text.gsub!(/([а-я\w\d,])«(.)/i, '\1 «\2') # new
|
254
|
+
text.gsub!(/» ([:,])/i, '»\1') # new
|
255
|
+
text.gsub!(/«$/, '»') # new
|
256
|
+
text.gsub!(/^»/, '«') # new
|
257
|
+
text.gsub!('.».', '».') # new
|
258
|
+
text.gsub!(/ »(.)/, ' «\1') # new
|
259
|
+
text.gsub!(/^«\s+/, '«') # new
|
260
|
+
text.gsub!(/\s+»$/, '»') # new
|
261
|
+
|
262
|
+
text
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Typograph
|
4
|
+
class Processor
|
5
|
+
|
6
|
+
DEFAULTS = {}
|
7
|
+
|
8
|
+
SAFE_BLOCKS = [
|
9
|
+
['<pre[^>]*>','</pre>'],
|
10
|
+
['<style[^>]*>','</style>'],
|
11
|
+
['<script[^>]*>','</script>'],
|
12
|
+
['<!--','-->'],
|
13
|
+
['<code[^>]*>','</code>']
|
14
|
+
]
|
15
|
+
|
16
|
+
def safe_blocks
|
17
|
+
@pattern ||= begin
|
18
|
+
pattern = SAFE_BLOCKS.map do |val|
|
19
|
+
val.join('.*?')
|
20
|
+
end.join('|')
|
21
|
+
Regexp.new("(#{pattern}|<[^>]*[\\s][^>]*>)", Regexp::IGNORECASE | Regexp::MULTILINE)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Вызывает типограф, обходя html-блоки и безопасные блоки
|
26
|
+
def process(str)
|
27
|
+
str = @profile.normalize(str)
|
28
|
+
|
29
|
+
@safe_blocks = {}
|
30
|
+
str.gsub!(safe_blocks) do |match|
|
31
|
+
key = "<#{@safe_blocks.length}>"
|
32
|
+
@safe_blocks[key] = match
|
33
|
+
key
|
34
|
+
end
|
35
|
+
|
36
|
+
str = @profile.process(str)
|
37
|
+
|
38
|
+
if @safe_blocks
|
39
|
+
str.gsub! /(<\d>)/ do |match|
|
40
|
+
@safe_blocks[match]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
@safe_blocks = {}
|
44
|
+
|
45
|
+
# выдераем дублирующиеся nowrap
|
46
|
+
str.gsub!(/(\<(\/?nobr)\>)+/i, '\1')
|
47
|
+
|
48
|
+
str
|
49
|
+
end
|
50
|
+
|
51
|
+
def initialize(options = {})
|
52
|
+
@profile = Adapters::Russian.new options
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/typograph.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
"����� ���������� �� ����", - ������ ��, -"��!"
|
2
|
+
������ ���������� �� ����, � ������ ��, -���!�
|
3
|
+
|
4
|
+
" �� ���� � ������ "
|
5
|
+
��� ���� � ������
|
6
|
+
|
7
|
+
������ ���������� ���� ��� �������� �����. ��� ���������,"���������" ��, ��������� �������.
|
8
|
+
������ ���������� ���� ��� �������� �����. ��� ���������, ����������� ��, ��������� �������.
|
9
|
+
|
10
|
+
""��-��""
|
11
|
+
���-���
|
12
|
+
|
13
|
+
���!,!
|
14
|
+
���!
|
15
|
+
|
16
|
+
��, , ��!
|
17
|
+
��, ��!
|
18
|
+
|
19
|
+
"�����.".
|
20
|
+
������.
|
21
|
+
|
22
|
+
���� ������::
|
23
|
+
���� ������:
|
24
|
+
|
25
|
+
���� ������: :
|
26
|
+
���� ������:
|
27
|
+
|
28
|
+
���� ������: : :
|
29
|
+
���� ������:
|
30
|
+
|
31
|
+
���� ������, , ,
|
32
|
+
���� ������,
|
33
|
+
|
34
|
+
���� ������; ; ; ; ;
|
35
|
+
���� ������;
|
36
|
+
|
37
|
+
"����������!!" - ���� ��!"
|
38
|
+
�����������!� � ���� ��!�
|
39
|
+
|
40
|
+
�������, �� ����� ���-������ O''Really?
|
41
|
+
�������, �� ����� ���-������ O’Really?
|
42
|
+
|
43
|
+
������: "������: "�������" � "�����, ����� "��������"", ����� ���� ����".
|
44
|
+
������: �������: ��������� � ������, ����� ����������, ����� ���� �����.
|
45
|
+
|
46
|
+
��� �����
|
47
|
+
���-�����
|
48
|
+
|
49
|
+
����� ��
|
50
|
+
�����-��
|