Как я маркирую эту строку в Ruby?

Существуют инструменты, предназначенные специально для работы с данными формата BED, которые вы бы хорошо изучили. bedtools , вероятно, является наиболее распространенным и простым в получении, и у него есть доступная оболочка для python , если вам абсолютно необходимо использовать python.

Инструмент multiIntersectBed - это то, что вам, вероятно, нужно, и его следует использовать довольно просто:

Пример использования:

== Input files: ==

 $ cat a.bed
 chr1  6   12
 chr1  10  20
 chr1  22  27
 chr1  24  30

 $ cat b.bed
 chr1  12  32
 chr1  14  30

 $ cat c.bed
 chr1  8   15
 chr1  10  14
 chr1  32  34

 $ cat sizes.txt
 chr1  5000

== Multi-intersect the files: ==

 $ multiIntersectBed -i a.bed b.bed c.bed
chr1    6       8       1       1       1       0       0
chr1    8       12      2       1,3     1       0       1
chr1    12      15      3       1,2,3   1       1       1
chr1    15      20      2       1,2     1       1       0
chr1    20      22      1       2       0       1       0
chr1    22      30      2       1,2     1       1       0
chr1    30      32      1       2       0       1       0
chr1    32      34      1       3       0       0       1

== Multi-intersect the files, with a header line (titles are the file names): ==

 $ multiIntersectBed -header -i a.bed b.bed c.bed
 chrom  start   end     num     list    a.bed   b.bed   c.bed
 chr1   6       8       1       1       1       0       0
 chr1   8       12      2       1,3     1       0       1
 chr1   12      15      3       1,2,3   1       1       1
 chr1   15      20      2       1,2     1       1       0
 chr1   20      22      1       2       0       1       0
 chr1   22      30      2       1,2     1       1       0
 chr1   30      32      1       2       0       1       0
 chr1   32      34      1       3       0       0       1

== Multi-intersect the files, with a header line and custom names: ==

 $ multiIntersectBed -header -i a.bed b.bed c.bed -names A B C
 chrom  start   end     num     list    A       B       C
 chr1   6       8       1       A       1       0       0
 chr1   8       12      2       A,C     1       0       1
 chr1   12      15      3       A,B,C   1       1       1
 chr1   15      20      2       A,B     1       1       0
 chr1   20      22      1       B       0       1       0
 chr1   22      30      2       A,B     1       1       0
 chr1   30      32      1       B       0       1       0
 chr1   32      34      1       C       0       0       1

== Multi-intersect the files, showing empty regions (note, requires -g): ==

 $ multiIntersectBed -header -i a.bed b.bed c.bed -names A B C -empty -g sizes.txt
 chrom  start   end     num     list    A       B       C
 chr1   0       6       0       none    0       0       0
 chr1   6       8       1       A       1       0       0
 chr1   8       12      2       A,C     1       0       1
 chr1   12      15      3       A,B,C   1       1       1
 chr1   15      20      2       A,B     1       1       0
 chr1   20      22      1       B       0       1       0
 chr1   22      30      2       A,B     1       1       0
 chr1   30      32      1       B       0       1       0
 chr1   32      34      1       C       0       0       1
 chr1   34      5000    0       none    0       0       0

Затем можно выполнить фильтрацию по 4-му столбцу, чтобы удовлетворить ваши оговоренные состояние для регионов.

12
задан the Tin Man 18 July 2012 в 19:29
поделиться

3 ответа

Для реального языка лексический анализатор сказал способ пойти - как Guss. Но если полный язык является только столь же сложным как Ваш пример, можно использовать этот быстрый взлом:

irb> text = %{Children^10 Health "sanitation management"^5}
irb> text.scan(/(?:(\w+)|"((?:\\.|[^\\"])*)")(?:\^(\d+))?/).map do |word,phrase,boost|
       { :keywords => (word || phrase).downcase, :boost => (boost.nil? ? nil : boost.to_i) }
     end
#=> [{:boost=>10, :keywords=>"children"}, {:boost=>nil, :keywords=>"health"}, {:boost=>5, :keywords=>"sanitation management"}]

При попытке проанализировать регулярный язык затем, то этот метод будет достаточен - хотя не потребовалось бы значительно большего количества сложностей для создания языка нерегулярным.

Быстрая разбивка regex:

  • \w+ соответствия любые ключевые слова единственного термина
  • (?:\\.|[^\\"]])* использование не получая круглые скобки ((?:...)) соответствовать содержанию завершенной двойной заключенной в кавычки строки - любой завершенный символ (\n, \", \\, и т.д.), или любой отдельный символ это не управляющий символ escape или кавычка конца.
  • "((?:\\.|[^\\"]])*)" получения только содержание заключенной в кавычки фразы ключевого слова.
  • (?:(\w+)|"((?:\\.|[^\\"])*)") соответствия любое ключевое слово - единственный термин или фраза, получая единственные условия в $1 и содержание фразы в $2
  • \d+ соответствует числу.
  • \^(\d+) получает число после каре (^). Так как это - третий набор получения круглых скобок, это будет caputred в $3.
  • (?:\^(\d+))? получает число после каре, если это там, соответствует пустой строке иначе.

String#scan(regex) соответствует regex против строки максимально много раз, вывод массив "соответствий". Если regex содержит получение parens, "соответствие" является массивом полученных объектов - так $1 становится match[0], $2 становится match[1], и т.д. Любая круглая скобка получения, которая не становится подобранной против части строки, отображается на a nil запись в получающемся "соответствии".

#map затем берет эти соответствия, использует некоторое волшебство блока повредить каждый полученный термин в различные переменные (мы, возможно, сделали do |match| ; word,phrase,boost = *match), и затем создает Ваши желаемые хеши. Точно один из word или phrase будет nil, так как оба не могут быть подобраны против входа, таким образом, (word || phrase) возвратится не -nil один, и #downcase преобразует его в весь нижний регистр. boost.to_i преобразует строку в целое число в то время как (boost.nil? ? nil : boost.to_i) гарантирует это nil повышения остаются nil.

17
ответ дан 2 December 2019 в 04:34
поделиться

Вот неустойчивое использование в качестве примера StringScanner. Это - код, который я просто адаптировал от Теста Ruby: JSON Парсинга, который имеет превосходное объяснение.

require 'strscan'

def test_parse
  text = %{Children^10 Health "sanitation management"^5}
  expected = [{:keywords=>"children", :boost=>10}, {:keywords=>"health", :boost=>nil}, {:keywords=>"sanitation management", :boost=>5}]


  assert_equal(expected, parse(text))
end

def parse(text)
  @input = StringScanner.new(text)

  output = []

  while keyword = parse_string || parse_quoted_string
    output << {
      :keywords => keyword,
      :boost => parse_boost
    }
    trim_space
  end

  output
end

def parse_string
  if @input.scan(/\w+/)
    @input.matched.downcase
  else
    nil
  end
end

def parse_quoted_string
  if @input.scan(/"/)
    str = parse_quoted_contents
    @input.scan(/"/) or raise "unclosed string"
    str
  else
    nil
  end
end

def parse_quoted_contents
  @input.scan(/[^\\"]+/) and @input.matched
end

def parse_boost
  if @input.scan(/\^/)
    boost = @input.scan(/\d+/)
    raise 'missing boost value' if boost.nil?
    boost.to_i
  else
    nil
  end
end

def trim_space
  @input.scan(/\s+/)
end
13
ответ дан 2 December 2019 в 04:34
поделиться

То, что Вы имеете, вот произвольная грамматика, и проанализировать его, что Вы действительно хотите, является лексическим анализатором - можно записать файл грамматики, который описал синтаксис, и затем используйте лексический анализатор для генерации рекурсивного синтаксического анализатора от грамматики.

Запись лексического анализатора (или даже рекурсивный синтаксический анализатор) не действительно тривиальна - хотя это - полезное упражнение в программировании - но можно найти список лексических анализаторов/синтаксических анализаторов Ruby в этом электронном письме здесь: http://newsgroups.derkeiler.com/Archive/Comp/comp.lang.ruby/2005-11/msg02233.html

RACC доступен как стандартный модуль Ruby 1.8, таким образом, я предлагаю, чтобы Вы сконцентрировались на том, что, даже если его руководству не действительно легко следовать и оно требует знакомства с yacc.

3
ответ дан 2 December 2019 в 04:34
поделиться