ruby_typograph 0.0.1.pre.7
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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.rspec +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +65 -0
- data/Rakefile +21 -0
- data/lib/typograph.rb +12 -0
- data/lib/typograph/adapter.rb +56 -0
- data/lib/typograph/processor.rb +56 -0
- data/lib/typograph/processors/quotes.rb +83 -0
- data/lib/typograph/processors/russian_grammar.rb +274 -0
- data/lib/typograph/version.rb +3 -0
- data/spec/helper.rb +5 -0
- data/spec/parse_error_spec.rb +61 -0
- data/spec/typograph_spec.rb +431 -0
- data/typographer.gemspec +25 -0
- metadata +105 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: df22ecd8c810f3eca7f45f19e0bff20ee3a254f1
|
4
|
+
data.tar.gz: bed8ba9ec1431e3f11d6c2115130ad90372f5473
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ea04e9d94b1602ea9bc0687c2d86badb6f26409187c6b4f0237cf3fa4293d0fbdc608f3b2e278d0a95d7a45bb2799f00c4914ba0b6263b7324ef04f471be945a
|
7
|
+
data.tar.gz: 4afcd23b08cb1ad3018c8e700a94910f560e35afae1edb6172769cf3acd9a89947d85f009d37747c8d6b88a016371e0471cbe15392ae4df2580bbfb984840212
|
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
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,65 @@
|
|
1
|
+
# Typograph
|
2
|
+
|
3
|
+
Gem for typographing russian and english texts.
|
4
|
+
|
5
|
+
##### Привязка союзов, предлогов
|
6
|
+
``` ruby
|
7
|
+
Typograph.process 'Я бы в лётчики б пошёл, пусть меня научат.'
|
8
|
+
> 'Я бы в летчики б пошел, пусть меня научат.'
|
9
|
+
```
|
10
|
+
|
11
|
+
##### Расстановка кавычек
|
12
|
+
``` ruby
|
13
|
+
Typograph.process '"Кавычки "второго уровня"" and "Quotes "second level""'
|
14
|
+
> '«Кавычки “второго уровня”» and “Quotes ‘second level’”'
|
15
|
+
```
|
16
|
+
|
17
|
+
##### Расстановка запятых перед а, но
|
18
|
+
``` ruby
|
19
|
+
Typograph.process 'Мало написать а запятые кто за тебя расставит.'
|
20
|
+
> '"Мало написать, а запятые кто за тебя расставит.'
|
21
|
+
```
|
22
|
+
|
23
|
+
##### Отсутствие запятых у "а"" и "но" после тире
|
24
|
+
``` ruby
|
25
|
+
Typograph.process 'Текст до тире – а теперь после'
|
26
|
+
> 'Текст до тире — а теперь после'
|
27
|
+
```
|
28
|
+
|
29
|
+
##### Расстановка правильного апострофа в английских текстах
|
30
|
+
``` ruby
|
31
|
+
Typograph.process "don't"
|
32
|
+
> 'don’t'
|
33
|
+
```
|
34
|
+
|
35
|
+
|
36
|
+
- Замена ё на е
|
37
|
+
- Удаление лишних пробелов
|
38
|
+
- Расстановка дефиса в предлогах из-за, из-под
|
39
|
+
- Расстановка дефиса перед -таки
|
40
|
+
- Расстановка дефиса после кое-, кой-
|
41
|
+
- Удаление пробела перед символом процент
|
42
|
+
- Удаление пробелов внутри скобок
|
43
|
+
- Выделение прямой речи
|
44
|
+
- Замена (R) на символ зарегистрированной торговой марки
|
45
|
+
- Замена (c) на символ копирайт
|
46
|
+
- Замена (tm) на символ торговой марки
|
47
|
+
- Замена дробей 1/2, 1/4, 3/4 на соответствующие символы
|
48
|
+
- Расстановка пробелов перед сокращениями см., им.
|
49
|
+
- Расстановка пробелов перед сокращениями гл., стр., рис., илл.
|
50
|
+
- Объединение сокращений и др.
|
51
|
+
- Расстановка пробелов в сокращениях г., ул., пер., д.
|
52
|
+
- Расстановка пробелов перед сокращениями dpi, lpi
|
53
|
+
|
54
|
+
### rspec
|
55
|
+
|
56
|
+
``` ruby
|
57
|
+
Finished in 0.07754 seconds
|
58
|
+
47 examples, 3 failures
|
59
|
+
|
60
|
+
Failed examples:
|
61
|
+
|
62
|
+
rspec ./spec/typograph_spec.rb:73 # .process Удаление пробелов перед знаками препинания
|
63
|
+
rspec ./spec/typograph_spec.rb:79 # .process Расстановка пробелов после знака препинания
|
64
|
+
rspec ./spec/typograph_spec.rb:103 # .process Выделение прямой речи
|
65
|
+
```
|
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
|
data/lib/typograph.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require "typograph/version"
|
2
|
+
require "typograph/adapter"
|
3
|
+
require "typograph/processors/quotes"
|
4
|
+
require "typograph/processors/russian_grammar"
|
5
|
+
require "typograph/processor"
|
6
|
+
|
7
|
+
module Typograph
|
8
|
+
def self.process(text="", options={})
|
9
|
+
return "" if text.nil?
|
10
|
+
Processor.new(options).process(text)
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'htmlentities'
|
4
|
+
|
5
|
+
module Typograph
|
6
|
+
class Adapter
|
7
|
+
|
8
|
+
SPECIAL = {
|
9
|
+
:lsquo => '‘',
|
10
|
+
:rsquo => '’',
|
11
|
+
:sbquo => '‚',
|
12
|
+
:ldquo => '“',
|
13
|
+
:rdquo => '”',
|
14
|
+
:bdquo => '„',
|
15
|
+
:lsaquo => '‹',
|
16
|
+
:rsaquo => '›',
|
17
|
+
:quot => '"',
|
18
|
+
:grave => '`',
|
19
|
+
:laquo => '«',
|
20
|
+
:raquo => '»',
|
21
|
+
:acute => '´',
|
22
|
+
:hellip => '…',
|
23
|
+
:ndash => '–',
|
24
|
+
:mdash => '—',
|
25
|
+
:nbsp => "\xA0",
|
26
|
+
:shy => "\xAD",
|
27
|
+
:cent => '¢',
|
28
|
+
:pound => '£',
|
29
|
+
:curren => '¤',
|
30
|
+
:yen => '¥',
|
31
|
+
:sect => '§',
|
32
|
+
:sup2 => '²',
|
33
|
+
:sup3 => '³'
|
34
|
+
}
|
35
|
+
|
36
|
+
def initialize(options={})
|
37
|
+
@options = options
|
38
|
+
end
|
39
|
+
|
40
|
+
def process(text)
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
def sym_to_char(sym)
|
45
|
+
res = SPECIAL[sym]
|
46
|
+
raise ArgumentError, "Unknown sym #{sym}" unless res
|
47
|
+
res
|
48
|
+
end
|
49
|
+
|
50
|
+
def normalize(str)
|
51
|
+
str.gsub!(/ | /, ' ')
|
52
|
+
str.chomp(" \r\n\t")
|
53
|
+
HTMLEntities.new.decode(str)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,56 @@
|
|
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 initialize(options={})
|
17
|
+
@adapter = Adapter.new options
|
18
|
+
@russian_grammar = Processors::RussianGrammar.new options
|
19
|
+
@quotes = Processors::Quotes.new options
|
20
|
+
end
|
21
|
+
|
22
|
+
def safe_blocks
|
23
|
+
@pattern ||= begin
|
24
|
+
pattern = SAFE_BLOCKS.map do |val|
|
25
|
+
val.join('.*?')
|
26
|
+
end.join('|')
|
27
|
+
Regexp.new("(#{pattern}|<[^>]*[\\s][^>]*>)", Regexp::IGNORECASE | Regexp::MULTILINE)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def process(str)
|
32
|
+
str = @adapter.normalize(str)
|
33
|
+
|
34
|
+
@safe_blocks = {}
|
35
|
+
str.gsub!(safe_blocks) do |match|
|
36
|
+
key = "<#{@safe_blocks.length}>"
|
37
|
+
@safe_blocks[key] = match
|
38
|
+
key
|
39
|
+
end
|
40
|
+
|
41
|
+
str = @quotes.process str
|
42
|
+
str = @russian_grammar.process str
|
43
|
+
|
44
|
+
|
45
|
+
if @safe_blocks
|
46
|
+
str.gsub! /(<\d>)/ do |match|
|
47
|
+
@safe_blocks[match]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
@safe_blocks = {}
|
51
|
+
|
52
|
+
str
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module Typograph
|
2
|
+
module Processors
|
3
|
+
class Quotes
|
4
|
+
|
5
|
+
SPECIAL = {
|
6
|
+
:lsquo => '‘',
|
7
|
+
:rsquo => '’',
|
8
|
+
:sbquo => '‚',
|
9
|
+
:ldquo => '“',
|
10
|
+
:rdquo => '”',
|
11
|
+
:bdquo => '„',
|
12
|
+
:quot => '"',
|
13
|
+
:grave => '`',
|
14
|
+
:laquo => '«',
|
15
|
+
:raquo => '»',
|
16
|
+
:acute => '´',
|
17
|
+
}
|
18
|
+
RU = 'А-я'
|
19
|
+
EN = 'A-z'
|
20
|
+
|
21
|
+
def initialize(options)
|
22
|
+
@options = options
|
23
|
+
end
|
24
|
+
|
25
|
+
def process(str)
|
26
|
+
if @options.nil? || @options[:only].nil?
|
27
|
+
str = replace_russian_quotes str
|
28
|
+
str = replace_english_quotes str
|
29
|
+
else
|
30
|
+
if @options[:only].include? :ru
|
31
|
+
str = replace_russian_quotes str, RU+EN
|
32
|
+
elsif @options[:only].include? :en
|
33
|
+
str = replace_english_quotes str, RU+EN
|
34
|
+
end
|
35
|
+
end
|
36
|
+
str
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def replace_russian_quotes(str,lang=RU)
|
42
|
+
left1 = SPECIAL[:laquo]
|
43
|
+
right1 = SPECIAL[:raquo]
|
44
|
+
left2 = SPECIAL[:ldquo]
|
45
|
+
right2 = SPECIAL[:rdquo]
|
46
|
+
str = replace_quotes str, left1, right1, left2, right2, lang
|
47
|
+
end
|
48
|
+
|
49
|
+
def replace_english_quotes(str,lang=EN)
|
50
|
+
left1 = SPECIAL[:ldquo]
|
51
|
+
right1 = SPECIAL[:rdquo]
|
52
|
+
left2 = SPECIAL[:lsquo]
|
53
|
+
right2 = SPECIAL[:rsquo]
|
54
|
+
str = replace_quotes str, left1, right1, left2, right2, lang
|
55
|
+
end
|
56
|
+
|
57
|
+
def replace_quotes(str,left1,right1,left2,right2,letters)
|
58
|
+
replace_quotes = lambda do
|
59
|
+
old_str = String.new(str)
|
60
|
+
str.gsub!(Regexp.new("(\"|\')([#{letters}].*?[^\\s])\\1", Regexp::MULTILINE | Regexp::IGNORECASE)) do |match|
|
61
|
+
inside, before, after = $2, $`, $'
|
62
|
+
if after.match(/^([^<]+>|>)/) || before.match(/<[^>]+$/)
|
63
|
+
match
|
64
|
+
else
|
65
|
+
"#{left1}#{inside}#{right1}"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
old_str != str
|
69
|
+
end
|
70
|
+
while replace_quotes.call do end
|
71
|
+
replace_second_level_quotes = lambda do
|
72
|
+
regexp = "(#{left1}([^#{right1},.])*)#{left1}(.*)#{right1}(.*#{right1})"
|
73
|
+
str.gsub! Regexp.new(regexp, Regexp::MULTILINE | Regexp::IGNORECASE) do |text|
|
74
|
+
"#{$1}#{left2}#{$3}#{right2}#{$4}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
while replace_second_level_quotes.call do end
|
78
|
+
str
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,274 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Typograph
|
4
|
+
module Processors
|
5
|
+
class RussianGrammar
|
6
|
+
|
7
|
+
OPTIONS = {
|
8
|
+
:ndash => '–',
|
9
|
+
:mdash => '—',
|
10
|
+
:minus => '-',
|
11
|
+
:orphan => false
|
12
|
+
}
|
13
|
+
|
14
|
+
def initialize(options={})
|
15
|
+
@options = OPTIONS.dup.merge(options)
|
16
|
+
|
17
|
+
@ndash = @options[:ndash]
|
18
|
+
@mdash = @options[:mdash]
|
19
|
+
@minus = @options[:minus]
|
20
|
+
|
21
|
+
@abbr = 'ООО|ОАО|ЗАО|ЧП|ИП|НПФ|НИИ|ООО\p{Zs}ТПК'
|
22
|
+
@prepos = 'а|в|во|вне|и|к|о|с|у|со|об|обо|от|ото|то|на|не|ни|но|из|изо|за|уж|на|по|подо|пред|предо|про|над|надо|как|без|безо|да|до|там|ещё|их|ко|меж|между|перед|передо|около|через|сквозь|при|я'
|
23
|
+
# что|для|или|под
|
24
|
+
@metrics = 'мм|см|м|км'
|
25
|
+
@measure = "#{@metrics}|г|кг|б|кб|мб|гб|dpi|px"
|
26
|
+
@shortages = 'г|гр|тов|пос|c|ул|д|пер|м|зам|им|бул'
|
27
|
+
@money = 'руб\.|долл\.|евро|у\.е\.'
|
28
|
+
@countables = 'млн|тыс'
|
29
|
+
|
30
|
+
@rules_strict = rules_strict
|
31
|
+
@rules_symbols = rules_symbols
|
32
|
+
@rules_braces = rules_braces
|
33
|
+
@rules_main = rules_main
|
34
|
+
@rules_main[/(\s)(\S+)\Z/] = ' \2' if options[:orphan]
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
def process(str)
|
39
|
+
str = apply_rules @rules_strict, str # Сначала применим строгие правила: пробелы, запятые
|
40
|
+
str = apply_rules @rules_symbols, str
|
41
|
+
str = apply_rules @rules_main, str
|
42
|
+
str = apply_rules @rules_braces, str
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def apply_rules(rules, str)
|
48
|
+
res = str.dup
|
49
|
+
rules.each do |rul, rep|
|
50
|
+
str.gsub!(rul, rep)
|
51
|
+
end
|
52
|
+
str
|
53
|
+
end
|
54
|
+
|
55
|
+
def rules_strict
|
56
|
+
{
|
57
|
+
# Много пробелов или табуляций -> один пробел
|
58
|
+
/( |\t)+/ => ' ',
|
59
|
+
# Запятые после «а» и «но». Если уже есть — не ставим.
|
60
|
+
/([а-яA-я0-9])\s(а|но)\s/ => '\1, \2 ',
|
61
|
+
}
|
62
|
+
end
|
63
|
+
|
64
|
+
def rules_symbols
|
65
|
+
{
|
66
|
+
# Лишние знаки.
|
67
|
+
# TODO: сделать красиво
|
68
|
+
/([^!])!!([^!])/ => '\1!\2',
|
69
|
+
/([^?])\?\?([^?])/ => '\1?\2',
|
70
|
+
/(\p{L})\s*\.\.(\p{Zs})/ => '\1.\2', # new
|
71
|
+
/(\p{L});[;\s]*(;)/ => '\1;', # new
|
72
|
+
/(\p{L}),[,\s]*(,)/ => '\1,', # new
|
73
|
+
/(\p{L}):[:\s]*(:)/ => '\1:', # new
|
74
|
+
|
75
|
+
/([!\?])\s*(!\s*)[!\s]*(!)/ => '\1!!', # new
|
76
|
+
/(\?\s*)(\?\s*)[\?\s]*(\?)/ => '???', # new
|
77
|
+
/(\.\s*)(\.\s*)[\.\s]*(\.)/ => '...', # new
|
78
|
+
/(,\s*)[,\s]*(,)/ => ',', # new
|
79
|
+
/;{2,}/ => ';', # new
|
80
|
+
/,{2,}/ => ',', # new
|
81
|
+
/:{2,}/ => ':', # new
|
82
|
+
|
83
|
+
# /([;,:])(\S)/ => '\1 \2', # new
|
84
|
+
|
85
|
+
# Занятная комбинация
|
86
|
+
/!\?/ => '?!',
|
87
|
+
|
88
|
+
# Знаки (c), (r), (tm)
|
89
|
+
/\((c|с)\)/i => '©',
|
90
|
+
/\(r\)/i => '<sup><small>®</small></sup>',
|
91
|
+
/\(tm\)/i => '™',
|
92
|
+
|
93
|
+
# От 2 до 5 знака точки подряд - на знак многоточия (больше - мб авторской задумкой).
|
94
|
+
/\s*\.{2,5}/ => '…',
|
95
|
+
|
96
|
+
# Дроби
|
97
|
+
# TODO: найти замену \b
|
98
|
+
/\b1\/2\b/ => '½',
|
99
|
+
/\b1\/3\b/ => '⅓',
|
100
|
+
/\b2\/3\b/ => '⅔',
|
101
|
+
/\b1\/4\b/ => '¼',
|
102
|
+
/\b3\/4\b/ => '¾',
|
103
|
+
/\b1\/5\b/ => '⅕',
|
104
|
+
/\b2\/5\b/ => '⅖',
|
105
|
+
/\b3\/5\b/ => '⅗',
|
106
|
+
/\b4\/5\b/ => '⅘',
|
107
|
+
/\b1\/6\b/ => '⅙',
|
108
|
+
/\b5\/6\b/ => '⅚',
|
109
|
+
/\b1\/8\b/ => '⅛',
|
110
|
+
/\b3\/8\b/ => '⅜',
|
111
|
+
/\b5\/8\b/ => '⅝',
|
112
|
+
/\b7\/8\b/ => '⅞',
|
113
|
+
|
114
|
+
# LО'Лайт, O'Reilly
|
115
|
+
/([A-Z])''?([а-яА-Яa-zA-Z])/i => '\1’\2',
|
116
|
+
|
117
|
+
/'/ => ''',
|
118
|
+
|
119
|
+
# Размеры 10x10, правильный знак + убираем лишние пробелы
|
120
|
+
/(\p{Nd}+)\p{Zs}{0,}?[x|X|х|Х|*]\p{Zs}{0,}(\p{Nd}+)/ => '\1×\2',
|
121
|
+
|
122
|
+
# +-
|
123
|
+
/([^\+]|^)\+\/?-/ => '\1±',
|
124
|
+
|
125
|
+
# Стрелки
|
126
|
+
/([^-]|^)->/ => '\1→',
|
127
|
+
/<-([^-]|$)/ => '←\1'
|
128
|
+
}
|
129
|
+
end
|
130
|
+
|
131
|
+
def rules_braces
|
132
|
+
{
|
133
|
+
# Оторвать скобку от слова
|
134
|
+
/(\p{L})\(/ => '\1 (',
|
135
|
+
# Слепляем скобки со словами
|
136
|
+
/\( /m => '(',
|
137
|
+
/ \)/m => ')'
|
138
|
+
}
|
139
|
+
end
|
140
|
+
|
141
|
+
def rules_main
|
142
|
+
{
|
143
|
+
# Конфликт с «газо- и электросварка»
|
144
|
+
# Оторвать тире от слова
|
145
|
+
# /(\p{L})- / => '\1 - ',
|
146
|
+
|
147
|
+
# P.S., P.P.S - конфликтует с правилом инициалов.
|
148
|
+
'P.P.S.' => '<nobr>P. P. S.</nobr>',
|
149
|
+
/([^.]|^)P\.S\./ => '\1<nobr>P. S.</nobr>',
|
150
|
+
# /и( |\s)?т( |\s)?\.?д( |\s)?\.{0,2}/ => "<nobr>и т. д.</nobr>",
|
151
|
+
# /и( |\s)?т( |\s)?\.?п( |\s)?\.{0,2}/ => "<nobr>и т. п.</nobr>",
|
152
|
+
# /в( |\s)?т( |\s)?\.?ч( |\s)?\.{0,2}/ => "<nobr>в т. ч.</nobr>",
|
153
|
+
|
154
|
+
# Знаки с предшествующим пробелом… нехорошо!
|
155
|
+
# -/(\p{L}|>|\p{Nd}) +([?!:,;…])/ => '\1\2',
|
156
|
+
# /([?!:,;])(\p{L}|<)/ => '\1 \2',
|
157
|
+
# Для точки отдельно
|
158
|
+
/(\p{L})\p{Zs}(?:\.)(\p{Zs}|$)/ => '\1.\2',
|
159
|
+
# Но перед кавычками пробелов не ставим
|
160
|
+
/([?!:,;\.])\p{Zs}(»)/ => '\1\2',
|
161
|
+
|
162
|
+
# Неразрывные названия организаций и абревиатуры форм собственности
|
163
|
+
# ~ почему не один ?
|
164
|
+
# ! названия организаций тоже могут содержать пробел !
|
165
|
+
/(#{@abbr})\p{Zs}+(«[^»]*»)/ => '<nobr>\1 \2</nobr>',
|
166
|
+
|
167
|
+
# Нельзя отрывать сокращение от относящегося к нему слова.
|
168
|
+
# Например: тов. Сталин, г. Воронеж
|
169
|
+
# Ставит пробел, если его нет.
|
170
|
+
/(^|[^a-zA-Zа-яА-Я])(#{@shortages})\.\s?([А-Я0-9]+)/m => '\1\2. \3',
|
171
|
+
/(^|[^a-zA-Zа-яА-Я])(см)\.\s?([А-Яа-я]+)/m => '\1\2. \3',
|
172
|
+
|
173
|
+
# Не отделять стр., с. и т.д. от номера.
|
174
|
+
/(стр|с|табл|рис|илл|гл)\.\p{Zs}*(\p{Nd}+)/mi => '\1. \2',
|
175
|
+
|
176
|
+
# Не разделять 2007 г., ставить пробел, если его нет. Ставит точку, если её нет.
|
177
|
+
/(\p{Nd}+)\p{Zs}*([гГ])\.\s/m => '\1 \2. ',
|
178
|
+
/(\p{Nd}+)\p{Zs}*-\p{Zs}*(\p{Nd}+)г\.?г\./ => "<nobr>\\1—\\2 гг.</nobr>",
|
179
|
+
/(\d\d\.\d\d\.\d\d\d?\d?)(\s| )*г\.?(\s| )/ => "<nobr>\\1 г.</nobr> ",
|
180
|
+
|
181
|
+
# Неразрывный пробел между цифрой и единицей измерения
|
182
|
+
/(\p{Nd}+)\s*(#{@measure})/m => '\1 \2',
|
183
|
+
|
184
|
+
# Сантиметр и другие ед. измерения в квадрате, кубе и т.д.
|
185
|
+
/(\p{Zs}#{@metrics})2/ => '\1²',
|
186
|
+
/(\p{Zs}#{@metrics})3/ => '\1³',
|
187
|
+
/(\p{Zs}#{@metrics})(\p{Nd}+)/ => '\1<sup>\2</sup>',
|
188
|
+
|
189
|
+
# Знак дефиса или два знака дефиса подряд — на знак длинного тире.
|
190
|
+
# + Нельзя разрывать строку перед тире, например: Знание — сила, Курить — здоровью вредить.
|
191
|
+
/\p{Zs}+(?:--?|—)(?=\p{Zs})/ => " #{@mdash}",
|
192
|
+
/^(?:--?|—)(?=\p{Zs})/ => @mdash,
|
193
|
+
|
194
|
+
# Прямая речь
|
195
|
+
/(?:^|\s+)(?:--?|—)(?=\p{Zs})/ => '\0',
|
196
|
+
|
197
|
+
# Знак дефиса, ограниченный с обоих сторон цифрами — на знак короткого тире.
|
198
|
+
/(?<=\p{Nd})-(?=\p{Nd})/ => @minus,
|
199
|
+
|
200
|
+
# Знак дефиса, ограниченный с обоих сторон пробелами — на знак длинного тире.
|
201
|
+
/(\s)(–|–)(\s)/ => " #{@mdash} ",
|
202
|
+
|
203
|
+
# Знак дефиса, идущий после тэга и справа пробел — на знак длинного тире.
|
204
|
+
/(?<=>)(–|–|-)(\s)/ => "#{@mdash} ",
|
205
|
+
|
206
|
+
# Расстановка дефиса перед -ка, -де, -кась
|
207
|
+
# /\b(\S+)[\s-](ка|де|кась)\b/ => "<nobr>\\1#{ndash}\\2</nobr>",
|
208
|
+
|
209
|
+
# Расстановка дефиса после кое-, кой-
|
210
|
+
/\b(кое|кой)[\s-](как|кого|какой)\b/i => "<nobr>\\1#{@ndash}\\2</nobr>",
|
211
|
+
|
212
|
+
# Расстановка дефиса перед -то, -либо, -нибудь
|
213
|
+
### to od /(кто|что|где|когда|почему|зачем|кем|чем|как|чего)(\s|-|–|—| )+(либо|нибудь|то)([^:]|$)/i => "<nobr>\\1#{ndash}\\3</nobr>\\4",
|
214
|
+
|
215
|
+
# Расстановка дефиса перед -таки
|
216
|
+
/(все)(\s|-|–|—| )+(таки)/i => "<nobr>\\1#{@ndash}\\3</nobr>",
|
217
|
+
|
218
|
+
# Расстановка дефисов в предлогах «из-за», «из-под», «по-над», «по-под».
|
219
|
+
/\b(из)[\s-]?(за|под)\b/i => "<nobr>\\1#{@ndash}\\2</nobr>",
|
220
|
+
/\b(по)[\s-]?(над|под)\b/i => "<nobr>\\1#{@ndash}\\2</nobr>",
|
221
|
+
|
222
|
+
# Нельзя оставлять в конце строки предлоги и союзы
|
223
|
+
/(?<=\p{Zs}|^|\p{^L})(#{@prepos})(\s+)/i => '\1 ',
|
224
|
+
|
225
|
+
# Нельзя отрывать частицы бы, ли, же от предшествующего слова, например: как бы, вряд ли, так же.
|
226
|
+
/(?<=\p{^Zs})(\p{Zs}+)(ж|бы|б|же|ли|ль|либо)(?=(<.*?>)*[\p{Zs})!?.…])/i => ' \2',
|
227
|
+
# |или
|
228
|
+
|
229
|
+
# Неразрывный пробел после инициалов.
|
230
|
+
/([А-ЯA-Z]\.)\s?([А-ЯA-Z]\.)\p{Zs}?([А-ЯA-Z][а-яa-z]+)/m => '\1\2 \3',
|
231
|
+
|
232
|
+
# Сокращения сумм не отделяются от чисел.
|
233
|
+
/(\p{Nd}+)\p{Zs}?(#{@countables})/m => '\1 \2',
|
234
|
+
|
235
|
+
# «уе» в денежных суммах
|
236
|
+
/(\p{Nd}+|#{@countables})\p{Zs}?уе/m => '\1 у.е.',
|
237
|
+
|
238
|
+
# Денежные суммы, расставляя пробелы в нужных местах.
|
239
|
+
/(\p{Nd}+|#{@countables})\p{Zs}?(#{@money})/m => '\1 \2',
|
240
|
+
|
241
|
+
# Неразрывные пробелы в кавычках
|
242
|
+
# "/($sym[lquote]\S*)(\s+)(\S*$sym[rquote])/U" => '\1'.\sym["nbsp"].'\3',
|
243
|
+
|
244
|
+
# Телефоны
|
245
|
+
/(?:тел\.?\/?факс:?\s?\((\d+)\))/i => 'тел./факс: (\1)',
|
246
|
+
|
247
|
+
/тел[:\.] ?(\p{Nd}+)/m => '<nobr>тел: \1</nobr>',
|
248
|
+
|
249
|
+
# Номер версии программы пишем неразрывно с буковкой v.
|
250
|
+
/([vв]\.) ?(\p{Nd})/i => '\1 \2',
|
251
|
+
/(\p{L}) ([vв]\.)/i => '\1 \2',
|
252
|
+
|
253
|
+
# % не отделяется от числа
|
254
|
+
/(\p{Nd}+)\p{Zs}+%/ => '\1%',
|
255
|
+
|
256
|
+
# IP-адреса рвать нехорошо
|
257
|
+
/(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})?)/ =>
|
258
|
+
'<nobr>\0</nobr>',
|
259
|
+
|
260
|
+
# Делаем неразрывными слова с дефисом.
|
261
|
+
# Пример: "слово-слово", "слово-слово-слово".
|
262
|
+
/(\^|;)((\p{L}+((–|–|-)\p{L}+){1,2}))/ => '\1<nobr>\2</nobr>',
|
263
|
+
|
264
|
+
# Меняем ё на е и Ё на Е
|
265
|
+
/ё/ => 'е',
|
266
|
+
/Ё/ => 'Е',
|
267
|
+
|
268
|
+
}
|
269
|
+
end
|
270
|
+
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
data/spec/helper.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# $KCODE = "utf-8" if defined?($KCODE)
|
3
|
+
|
4
|
+
require "typograph"
|
5
|
+
require "rspec"
|
6
|
+
|
7
|
+
OPT = {
|
8
|
+
:ndash => '-'
|
9
|
+
}
|
10
|
+
|
11
|
+
describe 'errors' do
|
12
|
+
|
13
|
+
describe 'quotes' do
|
14
|
+
|
15
|
+
it '#1' do
|
16
|
+
text = "БМК «ПРОСТ»,Библиотека Тургенева приглашают на 2-е заседание дискуссионного клуба 'Дисккуб21'."
|
17
|
+
text_processed = "БМК «ПРОСТ»,Библиотека Тургенева приглашают на 2-е заседание дискуссионного клуба «Дисккуб21»."
|
18
|
+
Typograph.process(text, OPT).should eq text_processed
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
it '#2' do
|
23
|
+
text = "Аля Самохина, создатель блога wholesomeway.net, и Аня Сидорова, организатор фитнес-туров Fitness travel, научат готовить необычные блюда из фруктов, зелени, орехов и других полезных продуктов:\n\n"+
|
24
|
+
"— смузи \"Бодрость зелени\";\n\n" +
|
25
|
+
"— мороженое \"Банановый рассвет\";\n\n" +
|
26
|
+
"— пирожное \"Баунти\".\n\n" +
|
27
|
+
"Мастер-класс Али Самохиной и Ани Сидоровой состоится в рамках Делай феста — в секции 'Ланчи-бранчи'. Полная программа «Делай феста»\n"
|
28
|
+
|
29
|
+
text_processed = "Аля Самохина, создатель блога wholesomeway.net, и Аня Сидорова, организатор фитнес-туров Fitness travel, научат готовить необычные блюда из фруктов, зелени, орехов и других полезных продуктов:\n\n"+
|
30
|
+
"— смузи «Бодрость зелени»;\n\n" +
|
31
|
+
"— мороженое «Банановый рассвет»;\n\n" +
|
32
|
+
"— пирожное «Баунти».\n\n" +
|
33
|
+
"Мастер-класс Али Самохиной и Ани Сидоровой состоится в рамках Делай феста — в секции «Ланчи-бранчи». Полная программа «Делай феста»\n"
|
34
|
+
|
35
|
+
Typograph.process(text, OPT).should eq text_processed
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
describe 'ampersand' do
|
41
|
+
it '#1' do
|
42
|
+
text = '<p>Воркшоп состоится в рамках «Делай феста» — в секции «Арт&Дизайн». Полная программа http://makefest.exchang.es/schedule</p>'
|
43
|
+
text_processed = "<p>Воркшоп состоится в рамках «Делай феста» — в секции «Арт&Дизайн». Полная программа http://makefest.exchang.es/schedule</p>"
|
44
|
+
Typograph.process(text, OPT).should eq text_processed
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
|
50
|
+
describe 'options' do
|
51
|
+
it 'only russian quotes' do
|
52
|
+
text = 'Тумбочка "staple x"'
|
53
|
+
text_processed = "Тумбочка «staple x»"
|
54
|
+
Typograph.process(text, only: [:ru]).should eq text_processed
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
end
|
@@ -0,0 +1,431 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# $KCODE = "utf-8" if defined?($KCODE)
|
3
|
+
|
4
|
+
require "typograph"
|
5
|
+
require "rspec"
|
6
|
+
|
7
|
+
OPT = {
|
8
|
+
:ndash => '-'
|
9
|
+
}
|
10
|
+
|
11
|
+
describe '.process' do
|
12
|
+
it 'Удаление лишних пробельных символов и табуляций' do
|
13
|
+
text = "В этом тексте \t много пробелов."
|
14
|
+
text_processed = 'В этом тексте много пробелов.'
|
15
|
+
Typograph.process(text, OPT).should eq text_processed
|
16
|
+
end
|
17
|
+
|
18
|
+
# it 'Удаление повторяющихся слов' do
|
19
|
+
# text = 'При при проверке текста обнаружились обнаружились повторяющиеся слова слова. Слова убраны.'
|
20
|
+
# text_processed = 'При проверке текста обнаружились повторяющиеся слова. Слова убраны.'
|
21
|
+
# Typograph.process(text, OPT).should eq text_processed
|
22
|
+
# end
|
23
|
+
|
24
|
+
it 'Расстановка запятых перед а, но' do
|
25
|
+
text = 'Мало написать а запятые кто за тебя расставит.'
|
26
|
+
text_processed = 'Мало написать, а запятые кто за тебя расставит.'
|
27
|
+
Typograph.process(text, OPT).should eq text_processed
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'Отсутствие запятых у "а"" и "но" после тире' do
|
31
|
+
text = 'Текст до тире – а теперь после'
|
32
|
+
text_processed = 'Текст до тире — а теперь после'
|
33
|
+
Typograph.process(text, OPT).should eq text_processed
|
34
|
+
end
|
35
|
+
|
36
|
+
# it 'Расстановка дефиса перед -то, -либо, -нибудь' do
|
37
|
+
# text = 'Кто то где то когда то как то что то чем то стукнул. И возможно чего нибудь бы получилось если б кто либо пришел.'
|
38
|
+
# text_processed = '<nobr>Кто-то</nobr> <nobr>где-то</nobr> <nobr>когда-то</nobr> <nobr>как-то</nobr> <nobr>что-то</nobr> <nobr>чем-то</nobr> стукнул. И возможно <nobr>чего-нибудь</nobr> бы получилось если б <nobr>кто-либо</nobr> пришел.'
|
39
|
+
# # Опять же что - то получилось, но как- то не так.
|
40
|
+
# Typograph.process(text, OPT).should eq text_processed
|
41
|
+
# end
|
42
|
+
|
43
|
+
# it 'Расстановка дефиса перед -ка, -де, -кась' do
|
44
|
+
# text = 'Возьми ка детка молока. А коль увижу де, что казнь ему мала, повешу тут же всех судей вокруг стола. Поди кась так. Планета Ка-Пэкс'
|
45
|
+
# text_processed = '<nobr>Возьми-ка</nobr> детка молока. А коль <nobr>увижу-де</nobr>, что казнь ему мала, повешу тут же всех судей вокруг стола. <nobr>Поди-кась</nobr> так. Планета Ка-Пэкс'
|
46
|
+
# Typograph.process(text, OPT).should eq text_processed
|
47
|
+
# end
|
48
|
+
|
49
|
+
it 'Расстановка дефиса после кое-, кой-' do
|
50
|
+
text = 'Кое как дошли. Кой кого встретили. Кое от кого, кое на чем, кой у кого, кое с чьим.'
|
51
|
+
text_processed = '<nobr>Кое-как</nobr> дошли. <nobr>Кой-кого</nobr> встретили. Кое от кого, кое на чем, кой у кого, кое с чьим.'
|
52
|
+
Typograph.process(text, OPT).should eq text_processed
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'Расстановка дефиса перед -таки' do
|
56
|
+
text = 'Секретарь, хотя и чувствовал свое слабое недовольство, все таки радовался наличию таких старушек в активе района. Но хоть и велик был соблазн, я таки успел себя побороть.'
|
57
|
+
text_processed = 'Секретарь, хотя и чувствовал свое слабое недовольство, <nobr>все-таки</nobr> радовался наличию таких старушек в активе района. Но хоть и велик был соблазн, я таки успел себя побороть.'
|
58
|
+
Typograph.process(text, OPT).should eq text_processed
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'Расстановка дефиса в предлогах из-за, из-под' do
|
62
|
+
text = 'Из за леса величаво выплывало солнце. Из под развесистой сирени вдруг с лаем выскочила собака.'
|
63
|
+
text_processed = '<nobr>Из-за</nobr> леса величаво выплывало солнце. <nobr>Из-под</nobr> развесистой сирени вдруг с лаем выскочила собака.'
|
64
|
+
Typograph.process(text, OPT).should eq text_processed
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'Удаление парных знаков препинания' do
|
68
|
+
text = 'Правда!? Правда!!! Неправда??? Честно?? Честно!! Проехали.. Задумчиво...'
|
69
|
+
text_processed = 'Правда?! Правда!!! Неправда??? Честно? Честно! Проехали. Задумчиво…'
|
70
|
+
Typograph.process(text, OPT).should eq text_processed
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'Удаление пробелов перед знаками препинания' do
|
74
|
+
text = 'Некоторые виды деревьев : ель ,сосна , берёза, дуб ; растут в наших лесах .'
|
75
|
+
text_processed = 'Некоторые виды деревьев: ель, сосна, береза, дуб; растут в наших лесах.'
|
76
|
+
Typograph.process(text, OPT).should eq text_processed
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'Расстановка пробелов после знака препинания' do
|
80
|
+
text = 'Так бывает.И вот так...И ещё вот так!..Бывает же???Что поделать. Вывод:верен.'
|
81
|
+
text_processed = 'Так бывает. И вот так… И ещё вот так!.. Бывает же??? Что поделать. Вывод: верен.'
|
82
|
+
Typograph.process(text, OPT).should eq text_processed
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'Удаление пробела перед символом процент' do
|
86
|
+
text = '100 %'
|
87
|
+
text_processed = '100%'
|
88
|
+
Typograph.process(text, OPT).should eq text_processed
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'Удаление пробелов внутри скобок' do
|
92
|
+
text = 'Текст( ( Внутри ) скобок ).'
|
93
|
+
text_processed = 'Текст ((Внутри) скобок).'
|
94
|
+
Typograph.process(text, OPT).should eq text_processed
|
95
|
+
end
|
96
|
+
|
97
|
+
# it 'Расстановка пробела перед скобками' do
|
98
|
+
# text = 'Текст(Внутри скобок).'
|
99
|
+
# text_processed = 'Текст (Внутри скобок).'
|
100
|
+
# Typograph.process(text, OPT).should eq text_processed
|
101
|
+
# end
|
102
|
+
|
103
|
+
it 'Выделение прямой речи' do
|
104
|
+
text = '- Я пошёл домой... - Может останешься? - Нет, ухожу.'
|
105
|
+
text_processed = '— Я пошёл домой… — Может останешься? — Нет, ухожу.'
|
106
|
+
Typograph.process(text, OPT).should eq text_processed
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'Привязка союзов, предлогов' do
|
110
|
+
text = 'Я бы в лётчики б пошёл, пусть меня научат.'
|
111
|
+
text_processed = 'Я бы в летчики б пошел, пусть меня научат.'
|
112
|
+
Typograph.process(text, OPT).should eq text_processed
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'Замена x на символ × в размерных единицах' do
|
116
|
+
text = '3х4, 3 х 6'
|
117
|
+
text_processed = '3×4, 3×6'
|
118
|
+
Typograph.process(text, OPT).should eq text_processed
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'Замена дробей 1/2, 1/4, 3/4 на соответствующие символы' do
|
122
|
+
text = '1/2, 1/4, 3/4, 123/432'
|
123
|
+
text_processed = '½, ¼, ¾, 123/432'
|
124
|
+
Typograph.process(text, OPT).should eq text_processed
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'Замена (R) на символ зарегистрированной торговой марки' do
|
128
|
+
text = '(r)'
|
129
|
+
text_processed = '<sup><small>®</small></sup>'
|
130
|
+
Typograph.process(text, OPT).should eq text_processed
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'Замена (c) на символ копирайт' do
|
134
|
+
text = '(c) Eugene Spearance'
|
135
|
+
text_processed = '© Eugene Spearance'
|
136
|
+
Typograph.process(text, OPT).should eq text_processed
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'Замена (tm) на символ торговой марки' do
|
140
|
+
text = 'ВасяПупкин(tm)'
|
141
|
+
text_processed = 'ВасяПупкин™'
|
142
|
+
Typograph.process(text, OPT).should eq text_processed
|
143
|
+
end
|
144
|
+
|
145
|
+
# it 'Тире в конце строки (стихотворная форма)' do
|
146
|
+
# text = %q{Раздобудь к утру ковёр -
|
147
|
+
# Шитый золотом узор!..
|
148
|
+
# Государственное дело, -
|
149
|
+
# Расшибись, а будь добёр!}
|
150
|
+
# text_processed = %q{Раздобудь к утру ковёр —<br />\nШитый золотом узор!..<br />\nГосударственное дело, —<br />\nРасшибись, а будь добёр!}
|
151
|
+
# Typograph.process(text, OPT).should eq text_processed
|
152
|
+
# end
|
153
|
+
|
154
|
+
it 'Расстановка знака минус между числами' do
|
155
|
+
text = '123-32'
|
156
|
+
text_processed = '123-32'
|
157
|
+
Typograph.process(text, OPT).should eq text_processed
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'Расстановка правильного апострофа в английских текстах' do
|
161
|
+
text = "don't"
|
162
|
+
text_processed = 'don’t'
|
163
|
+
Typograph.process(text, OPT).should eq text_processed
|
164
|
+
end
|
165
|
+
|
166
|
+
# it 'Замена символа параграф с привязкой к числу' do
|
167
|
+
# text = '§32, §IV'
|
168
|
+
# text_processed = '§ 32, § IV'
|
169
|
+
# Typograph.process(text, OPT).should eq text_processed
|
170
|
+
# end
|
171
|
+
|
172
|
+
# it 'Замена символа номер с привязкой к числу' do
|
173
|
+
# text = '№15Ф, №34/25'
|
174
|
+
# text_processed = '№ 15Ф, № 34/25'
|
175
|
+
# Typograph.process(text, OPT).should eq text_processed
|
176
|
+
# end
|
177
|
+
|
178
|
+
it 'Расстановка правильных «тройных» кавычек' do
|
179
|
+
text = 'Она добавила: "И цвет мой самый любимый - "эсмеральда"".'
|
180
|
+
text_processed = 'Она добавила: «И цвет мой самый любимый — “эсмеральда”».'
|
181
|
+
Typograph.process(text, OPT).should eq text_processed
|
182
|
+
end
|
183
|
+
|
184
|
+
# it 'Расстановка пробелов и привязка в денежных сокращениях' do
|
185
|
+
# text = '10,34руб., 23тыс.долл., 64 млн.евро, 34.3€, 56$, 3,65уе'
|
186
|
+
# text_processed = '10,34 руб., 23 тыс. долл., 64 млн. евро, 34.3 €, 56 $, 3,65 у.е.'
|
187
|
+
# Typograph.process(text, OPT).should eq text_processed
|
188
|
+
# end
|
189
|
+
|
190
|
+
# it 'Объединение сокращений и т.д., и т.п., в т.ч.' do
|
191
|
+
# text = 'Лес, газ, нефть и тд., и т.п.. Перины, подушки в тч. подушки-думки.'
|
192
|
+
# text_processed = 'Лес, газ, нефть <nobr>и т. д.</nobr>, <nobr>и т. п.</nobr> Перины, подушки <nobr>в т. ч.</nobr> <nobr>подушки-думки</nobr>.'
|
193
|
+
# Typograph.process(text, OPT).should eq text_processed
|
194
|
+
# end
|
195
|
+
|
196
|
+
it 'Расстановка пробелов перед сокращениями см., им.' do
|
197
|
+
text = 'Данные изложены в таблице см.цветной вкладыш. Дом им.Пушкина.'
|
198
|
+
text_processed = 'Данные изложены в таблице см. цветной вкладыш. Дом им. Пушкина.'
|
199
|
+
Typograph.process(text, OPT).should eq text_processed
|
200
|
+
end
|
201
|
+
|
202
|
+
it 'Расстановка пробелов перед сокращениями гл., стр., рис., илл.' do
|
203
|
+
text = 'Инструкцию см. гл. 8, стр.34, рис.3 или илл.3.'
|
204
|
+
text_processed = 'Инструкцию см. гл. 8, стр. 34, рис. 3 или илл. 3.'
|
205
|
+
Typograph.process(text, OPT).should eq text_processed
|
206
|
+
end
|
207
|
+
|
208
|
+
it 'Объединение сокращений и др.' do
|
209
|
+
text = 'Оля, Иван, Олег и др. ребята.'
|
210
|
+
text_processed = 'Оля, Иван, Олег и др. ребята.'
|
211
|
+
Typograph.process(text, OPT).should eq text_processed
|
212
|
+
end
|
213
|
+
|
214
|
+
it 'Расстановка пробелов в сокращениях г., ул., пер., д.' do
|
215
|
+
text = 'г.Тюмень, ул.Ленина, пер. Ленина, бул. Ленина, д. 4'
|
216
|
+
text_processed = 'г. Тюмень, ул. Ленина, пер. Ленина, бул. Ленина, д. 4'
|
217
|
+
Typograph.process(text, OPT).should eq text_processed
|
218
|
+
end
|
219
|
+
|
220
|
+
it 'Расстановка пробелов перед сокращениями dpi, lpi' do
|
221
|
+
text = 'Разрешение 300dpi (для офсета).'
|
222
|
+
text_processed = 'Разрешение 300 dpi (для офсета).'
|
223
|
+
Typograph.process(text, OPT).should eq text_processed
|
224
|
+
end
|
225
|
+
|
226
|
+
it 'Объединение сокращений P.S., P.P.S.' do
|
227
|
+
text = 'P.S. привет всем. P.P.S. и мне тоже.'
|
228
|
+
text_processed = '<nobr>P. S.</nobr> привет всем. <nobr>P. P. S.</nobr> и мне тоже.'
|
229
|
+
Typograph.process(text, OPT).should eq text_processed
|
230
|
+
end
|
231
|
+
|
232
|
+
# it 'Объединение в неразрывные конструкции слов с дефисом.' do
|
233
|
+
# text = 'Жёлто-оранжевый цвет. Ростов-на-Дону красивый город.'
|
234
|
+
# text_processed = '<nobr>Жёлто-оранжевый</nobr> цвет. <nobr>Ростов-на-Дону</nobr> красивый город.'
|
235
|
+
# Typograph.process(text, OPT).should eq text_processed
|
236
|
+
# end
|
237
|
+
|
238
|
+
# it 'Привязка сокращений форм собственности к названиям организаций' do
|
239
|
+
# text = 'ООО "Фирма Терминал", НИИ "ОблСнабВротКомпот"'
|
240
|
+
# text_processed = '<nobr>ООО «Фирма Терминал»</nobr>, <nobr>НИИ «ОблСнабВротКомпот»</nobr>'
|
241
|
+
# Typograph.process(text, OPT).should eq text_processed
|
242
|
+
# end
|
243
|
+
|
244
|
+
# it 'Объединение в неразрывные конструкции номеров телефонов' do
|
245
|
+
# text = '+7 (3452) 55-66-77, 8 905 555-55-55'
|
246
|
+
# text_processed = '<nobr>+7 (3452) 55-66-77</nobr>, <nobr>8 905 555-55-55</nobr>'
|
247
|
+
# Typograph.process(text, OPT).should eq text_processed
|
248
|
+
# end
|
249
|
+
|
250
|
+
# it 'Привязка сокращения ГОСТ к номеру' do
|
251
|
+
# text = 'Гост 5773-90 - российские стандартные форматы изданий'
|
252
|
+
# text_processed = '<nobr>ГОСТ 5773–90 —</nobr> российские стандартные форматы изданий'
|
253
|
+
# Typograph.process(text, OPT).should eq text_processed
|
254
|
+
# end
|
255
|
+
|
256
|
+
# it 'Установка пробельных символов в сокращении вольт' do
|
257
|
+
# text = '~23,5в'
|
258
|
+
# text_processed = '<nobr>~23,5 В</nobr>'
|
259
|
+
# Typograph.process(text, OPT).should eq text_processed
|
260
|
+
# end
|
261
|
+
|
262
|
+
# it 'Объединение триад чисел' do
|
263
|
+
# text = '123 456 789 руб. В стычке участвовало 3 200 человек.'
|
264
|
+
# text_processed = '123 456 789 руб. В стычке участвовало 3 200 человек.'
|
265
|
+
# Typograph.process(text, OPT).should eq text_processed
|
266
|
+
# end
|
267
|
+
|
268
|
+
it 'Объединение IP-адресов' do
|
269
|
+
text = 'Адрес localhost - 127.0.0.1'
|
270
|
+
text_processed = 'Адрес localhost — <nobr>127.0.0.1</nobr>'
|
271
|
+
Typograph.process(text, OPT).should eq text_processed
|
272
|
+
end
|
273
|
+
|
274
|
+
# it 'Установка тире и пробельных символов в периодах дат' do
|
275
|
+
# text = 'Это событие произошло между 1999-2001г.г., на стыке XX-XXIв.'
|
276
|
+
# text_processed = 'Это событие произошло между <nobr>1999—2001 гг.</nobr>, на стыке <nobr>XX—XXI вв.</nobr>'
|
277
|
+
# Typograph.process(text, OPT).should eq text_processed
|
278
|
+
# end
|
279
|
+
|
280
|
+
# it 'Привязка года к дате' do
|
281
|
+
# text = 'Документ был подписан 17.02.1983г. И утратил свою силу 07.03.93 года.'
|
282
|
+
# text_processed = 'Документ был подписан <nobr>17.02.1983 г.</nobr> И утратил свою силу 07.03.93 года.'
|
283
|
+
# Typograph.process(text, OPT).should eq text_processed
|
284
|
+
# end
|
285
|
+
|
286
|
+
# it 'Расстановка тире и объединение в неразрывные периоды дней' do
|
287
|
+
# text = 'Собеседования состоятся 14-24 сентября, в актовом зале с 11:30-13:00.'
|
288
|
+
# text_processed = 'Собеседования состоятся <nobr>14—24 сентября</nobr>, в актовом зале с <nobr>11:30—13:00</nobr>.'
|
289
|
+
# Typograph.process(text, OPT).should eq text_processed
|
290
|
+
# end
|
291
|
+
|
292
|
+
it 'Расстановка тире и объединение в неразрывные периоды месяцев' do
|
293
|
+
text = 'Выставка пройдёт в апреле-мае этого года.'
|
294
|
+
text_processed = 'Выставка пройдет в <nobr>апреле-мае</nobr> этого года.'
|
295
|
+
Typograph.process(text, OPT).should eq text_processed
|
296
|
+
end
|
297
|
+
|
298
|
+
it 'Привязка сокращений до н.э., н.э.' do
|
299
|
+
text = 'IV в до н.э, в V-VIвв до нэ., третий в. н.э.'
|
300
|
+
text_processed = 'IV в до н.э, в <nobr>V-VIвв</nobr> до нэ., третий в. н.э.'
|
301
|
+
Typograph.process(text, OPT).should eq text_processed
|
302
|
+
end
|
303
|
+
|
304
|
+
it 'Привязка инициалов к фамилиям' do
|
305
|
+
text = 'А.С.Пушкин, Пушкин А.С.'
|
306
|
+
text_processed = 'А.С. Пушкин, Пушкин А.С.'
|
307
|
+
Typograph.process(text, OPT).should eq text_processed
|
308
|
+
end
|
309
|
+
|
310
|
+
it 'Замена символа градус, плюс-минус' do
|
311
|
+
text = '+- 10, +/- 25'
|
312
|
+
text_processed = '± 10, ± 25'
|
313
|
+
Typograph.process(text, OPT).should eq text_processed
|
314
|
+
end
|
315
|
+
|
316
|
+
it 'Замена символов и привязка сокращений в размерных величинах: м, см, м2…' do
|
317
|
+
text = 'На лесопилку завезли 32 м3 леса, из которых 4м3 пустили под распил на 25мм доски, длинной по 6м.'
|
318
|
+
text_processed = 'На лесопилку завезли 32 м³ леса, из которых 4 м³ пустили под распил на 25 мм доски, длинной по 6 м.'
|
319
|
+
Typograph.process(text, OPT).should eq text_processed
|
320
|
+
end
|
321
|
+
|
322
|
+
it 'Повторное типографирование текста' do
|
323
|
+
text = '<p><nobr>Coca-Cola</nobr><sup><small>®</small></sup> — зарегистрированный товарный знак.</p>'
|
324
|
+
text_processed = '<p><nobr>Coca-Cola</nobr><sup><small>®</small></sup> — зарегистрированный товарный знак.</p>'
|
325
|
+
Typograph.process(text, OPT).should eq text_processed
|
326
|
+
end
|
327
|
+
|
328
|
+
it 'Обработка HTML' do
|
329
|
+
text = '<!-- В тексте попался комментарий -->'
|
330
|
+
text_processed = text.dup
|
331
|
+
Typograph.process(text, OPT).should eq text_processed
|
332
|
+
end
|
333
|
+
|
334
|
+
it 'Обработка CSS' do
|
335
|
+
text = %q{<style type="text/css">
|
336
|
+
SPAN.nobr { white-space: nowrap }
|
337
|
+
</style>}
|
338
|
+
text_processed = text.dup
|
339
|
+
Typograph.process(text, OPT).should eq text_processed
|
340
|
+
end
|
341
|
+
|
342
|
+
it 'Обработка JavaScript' do
|
343
|
+
text = "<script type='text/javascript'>document.write('Этот текст не должен быть типографирован.')</script>"
|
344
|
+
text_processed = text.dup
|
345
|
+
Typograph.process(text, OPT).should eq text_processed
|
346
|
+
end
|
347
|
+
|
348
|
+
it 'Обработка тегов <pre>' do
|
349
|
+
text = %q{<pre> Я не хотел бы
|
350
|
+
чтобы этот текст
|
351
|
+
был форматирован.</pre>}
|
352
|
+
text_processed = text.dup
|
353
|
+
Typograph.process(text, OPT).should eq text_processed
|
354
|
+
end
|
355
|
+
|
356
|
+
# it 'Выделение ссылок из текста' do
|
357
|
+
# text = 'В тексте встретилась ссылка: http://www.typograf.ru'
|
358
|
+
# text_processed = 'В тексте встретилась ссылка: <a href="http://www.typograf.ru">http://www.typograf.ru</a>'
|
359
|
+
# Typograph.process(text, OPT).should eq text_processed
|
360
|
+
# end
|
361
|
+
|
362
|
+
# it 'Выделение e-mail из текста' do
|
363
|
+
# text = 'В тексте встретился e-mail: mail@typograf.ru'
|
364
|
+
# text_processed = 'В тексте встретился <nobr>e-mail</nobr>: <a href="mailto:mail@typograf.ru">mail@typograf.ru</a>'
|
365
|
+
# Typograph.process(text, OPT).should eq text_processed
|
366
|
+
# end
|
367
|
+
|
368
|
+
# it 'Обработка списков' do
|
369
|
+
# text = ''
|
370
|
+
# # * Программное обеспечение
|
371
|
+
# # ** Операционные системы
|
372
|
+
# # +++ Windows XP
|
373
|
+
# # +++ Linux RedHat
|
374
|
+
# # +++ MacOS X
|
375
|
+
# # ** Текстовые радакторы
|
376
|
+
# # * Компьютеры
|
377
|
+
# text_processed = ''
|
378
|
+
# Typograph.process(text, OPT).should eq text_processed
|
379
|
+
# end
|
380
|
+
|
381
|
+
# it 'Выделение акронимов' do
|
382
|
+
# text = '<p>Все что вы хотели узнать о HTML.</p>'
|
383
|
+
# text_processed = '<p>Все что вы хотели узнать о <acronym title="HyperText Markup Language" lang="en">HTML</acronym>.</p>'
|
384
|
+
# Typograph.process(text, OPT).should eq text_processed
|
385
|
+
# end
|
386
|
+
|
387
|
+
it 'Меняем ё на е и Ё на Е' do
|
388
|
+
text = 'Ёж обыкновенный, или европейский ёж.'
|
389
|
+
text_processed = 'Еж обыкновенный, или европейский еж.'
|
390
|
+
Typograph.process(text, OPT).should eq text_processed
|
391
|
+
end
|
392
|
+
|
393
|
+
it 'Не трогаем ссылки в маркдауне' do
|
394
|
+
text = "Глава из книги Бориса Гройса «Поэтика политики»](http://theoryandpractice.ru/posts/6762-wikileaks-vosstanie-klerkov-glava-iz-knigi-borisa-groysa-poetika-politiki)"
|
395
|
+
text_processed = "Глава из книги Бориса Гройса «Поэтика политики»](http://theoryandpractice.ru/posts/6762-wikileaks-vosstanie-klerkov-glava-iz-knigi-borisa-groysa-poetika-politiki)"
|
396
|
+
Typograph.process(text, OPT).should eq text_processed
|
397
|
+
end
|
398
|
+
|
399
|
+
it 'Не трогам отсупы у тире, если с тире начинается строка' do
|
400
|
+
text = "Правах человека в России, и о ее месте в Совете Европы, и о коллективной памяти о преступлениях Советской власти.
|
401
|
+
Татьяна Добровольская
|
402
|
+
-------
|
403
|
+
**— Где и чему ты учишься, как давно?**
|
404
|
+
— Сейчас я учусь по обмену в Болонском университете на факультете политических наук. В Москве — в Высшей школе экономики"
|
405
|
+
text_processed = "Правах человека в России, и о ее месте в Совете Европы, и о коллективной памяти о преступлениях Советской власти.
|
406
|
+
Татьяна Добровольская
|
407
|
+
-------
|
408
|
+
**— Где и чему ты учишься, как давно?**
|
409
|
+
— Сейчас я учусь по обмену в Болонском университете на факультете политических наук. В Москве — в Высшей школе экономики"
|
410
|
+
Typograph.process(text, OPT).should eq text_processed
|
411
|
+
end
|
412
|
+
|
413
|
+
it "Лишнее тере с 'как' 'то'" do
|
414
|
+
text = "Я постараюсь ответить на твой вопрос так просто, как только смогу. Вот мой ответ:"
|
415
|
+
text_processed = "Я постараюсь ответить на твой вопрос так просто, как только смогу. Вот мой ответ:"
|
416
|
+
Typograph.process(text, OPT).should eq text_processed
|
417
|
+
end
|
418
|
+
|
419
|
+
it "should make english and russian quotes in the same string" do
|
420
|
+
text = '"Quotes" и "Кавычки"'
|
421
|
+
text_processed = '“Quotes” и «Кавычки»'
|
422
|
+
Typograph.process(text, OPT).should eq text_processed
|
423
|
+
end
|
424
|
+
|
425
|
+
it 'Quotes second level' do
|
426
|
+
text = '"Кавычки "второго уровня"" and "Quotes "second level""'
|
427
|
+
text_processed = "«Кавычки “второго уровня”» and “Quotes ‘second level’”"
|
428
|
+
Typograph.process(text, OPT).should eq text_processed
|
429
|
+
end
|
430
|
+
|
431
|
+
end
|
data/typographer.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'typograph/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = 'ruby_typograph'
|
8
|
+
gem.version = Typograph::VERSION
|
9
|
+
gem.authors = ['Tolia']
|
10
|
+
gem.email = ['toliademidov@gmail.com']
|
11
|
+
gem.description = %q{Gem for typographing russian and english texts.}
|
12
|
+
gem.summary = %q{Gem for typographing russian and english texts.}
|
13
|
+
gem.homepage = "https://github.com/Tolia/typograph"
|
14
|
+
gem.license = "MIT"
|
15
|
+
|
16
|
+
gem.files = `git ls-files`.split($/)
|
17
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
18
|
+
gem.test_files = gem.files.grep(%r{^(spec)/})
|
19
|
+
gem.require_paths = ["lib"]
|
20
|
+
|
21
|
+
gem.add_dependency 'htmlentities'
|
22
|
+
|
23
|
+
gem.add_development_dependency 'rake'
|
24
|
+
gem.add_development_dependency 'rspec'
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ruby_typograph
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1.pre.7
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tolia
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-12-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: htmlentities
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: Gem for typographing russian and english texts.
|
56
|
+
email:
|
57
|
+
- toliademidov@gmail.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- ".gitignore"
|
63
|
+
- ".rspec"
|
64
|
+
- Gemfile
|
65
|
+
- LICENSE.txt
|
66
|
+
- README.md
|
67
|
+
- Rakefile
|
68
|
+
- lib/typograph.rb
|
69
|
+
- lib/typograph/adapter.rb
|
70
|
+
- lib/typograph/processor.rb
|
71
|
+
- lib/typograph/processors/quotes.rb
|
72
|
+
- lib/typograph/processors/russian_grammar.rb
|
73
|
+
- lib/typograph/version.rb
|
74
|
+
- spec/helper.rb
|
75
|
+
- spec/parse_error_spec.rb
|
76
|
+
- spec/typograph_spec.rb
|
77
|
+
- typographer.gemspec
|
78
|
+
homepage: https://github.com/Tolia/typograph
|
79
|
+
licenses:
|
80
|
+
- MIT
|
81
|
+
metadata: {}
|
82
|
+
post_install_message:
|
83
|
+
rdoc_options: []
|
84
|
+
require_paths:
|
85
|
+
- lib
|
86
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - ">"
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: 1.3.1
|
96
|
+
requirements: []
|
97
|
+
rubyforge_project:
|
98
|
+
rubygems_version: 2.2.2
|
99
|
+
signing_key:
|
100
|
+
specification_version: 4
|
101
|
+
summary: Gem for typographing russian and english texts.
|
102
|
+
test_files:
|
103
|
+
- spec/helper.rb
|
104
|
+
- spec/parse_error_spec.rb
|
105
|
+
- spec/typograph_spec.rb
|