Мне нравится анализировать HTML с регулярными выражениями. Я не пытаюсь разбирать идиот HTML, который намеренно нарушен. Этот код является моим основным парсером (версия Perl):
$_ = join "",; tr/\n\r \t/ /s; s/\n/>\n/g; s/\n ?\n/\n/g;
s/^ ?\n//s; s/ $//s; print
Он называется htmlsplit, разбивает HTML на строки, с одним тегом или фрагментом текста в каждой строке. Затем линии могут быть обработаны другими текстовыми инструментами и сценариями, такими как grep , sed , Perl и т. Д. Я даже не шучу :) Наслаждайтесь.
Достаточно просто переписать мой скрипт Perl-all-first Perl в приятную поточную вещь, если вы хотите обрабатывать огромные веб-страницы. Но это действительно не обязательно.
Бьюсь об заклад, я заберусь для этого.
Против моего ожидая, что это получило некоторые upvotes, поэтому я предлагаю несколько правильных выражений:
/(<.*?>|[^<]+)\s*/g # get tags and text
/(\w+)="(.*?)"/g # get attibutes
Они хороши для XML / XHTML.
С небольшими вариациями он может справиться с беспорядочным HTML ... или сначала конвертировать HTML -> XHTML.
Лучший способ записи регулярных выражений - в Lex / Yacc стиль, а не непрозрачные однострочные или прокомментированные многострочные чудовища. Я не делал этого здесь; эти им едва ли нужны.
Вы можете использовать Supervision.Decider
для регистрации этих атрибутов.
object Test extends App {
implicit val system = ActorSystem("test")
implicit val mat = ActorMaterializer()
val testSupervisionDecider: Supervision.Decider = {
case ex: RuntimeException =>
println(s"some run time exception ${ex.getMessage}")
Supervision.Resume
case ex: Exception =>
//if you want to stop the stream
Supervision.Stop
}
val source = Source(List("1", "2", "3")).map { item =>
if (item == "2") {
throw new RuntimeException(s"$item")
} else {
item
}
}
source
.to(Sink.foreach(println(_)))
.withAttributes(ActorAttributes.supervisionStrategy(testSupervisionDecider))
.run
}
Вывод:
1
some run time exception 2
3
Не с Supervision.Decide
, но вы могли бы достичь этого по-другому.
Проверьте эту программу:
object Streams extends App{
implicit val system = ActorSystem("test")
implicit val mat = ActorMaterializer()
val source = Source(List("1", "2", "3")).map { item =>
Try {
if (item == "2") {
throw new RuntimeException("Error")
} else {
item
}
}
}
source
.alsoTo(
Flow[Try[String]]
.filter(_.isFailure)
.to(Sink.foreach(t => println("failure: " + t))))
.to(
Flow[Try[String]]
.filter(_.isSuccess)
.to(Sink.foreach(t => println("success " + t)))).run()
}
Выходы:
success Success(1)
failure: Failure(java.lang.RuntimeException: Error)
success Success(3)
Это несколько запутанно, но вы можете сделать это, обернув свою функцию отображения в потоке и используя flatMapConcat
примерно так:
Source(List(item1, item2, item3)).flatMapConcat { item =>
Source(List(item))
.map(mapF)
.withAttributes(ActorAttributes.supervisionStrategy { e: Throwable =>
logger.error("Exception in stream with itemId:" + item.id, e)
Supervision.Resume
})
}
def mapF(item: Item) =
if (item.property < 0) {
throw new RuntimeException("Error")
} else {
i
}
Это возможно, потому что у каждой стадии потока может быть своя собственная стратегия наблюдения .