Я предполагаю, что Вы на самом деле создаете дерево XML DOM, потому что Вы хотите проверить это, что входит в этот файл, допустимый XML, так как иначе Вы просто записали бы статическую строку в файл. Если проверка Вашего вывода является действительно Вашей целью, тогда я предложил бы
from xml.dom.minidom import parseString
doc = parseString("""<html>
<head>
<script type="text/javascript">
var a = 'I love &aacute; letters'
</script>
</head>
<body>
<h1>And I like the fact that 3 > 1</h1>
</body>
</html>""")
with open("foo.xhtml", "w") as f:
f.write( doc.toxml() )
, Это позволяет Вам просто записать XML, который Вы хотите произвести, для проверки этого это корректно (так как parseString повысит исключение, если это будет недопустимо), и имейте намного более хороший взгляд кода.
, По-видимому, Вы только пишете тому же статическому XML каждый раз и хотите некоторую замену. В этом случае я имел бы строки как
var a = '%(message)s'
и затем использовал бы оператор %, чтобы сделать замену, как
</html>""" % {"message": "I love &aacute; letters"})
Итераторы также ленивы (хотя и не очень функциональны, так как их можно выполнять только один раз). Таким образом, вы можете сделать это следующим образом:
def correct(word: String) = {
val sets = List[String => Set[String]](
x => known(Set(x)), x => known(edits1(x)), known_edits2
).elements.map(_(word))
sets find { !_.isEmpty } match {
case Some(candidates: Set[String]) => candidates.reduceLeft { (res, n) => if (NWORDS(res) > NWORDS(n)) res else n }
case None => word
}
}
В качестве бонуса метод find () итератора не вызывает оценку следующего элемента.
Это сработает? Синтаксис _
является частично применяемой функцией, и, используя (ленивый) поток
, я гарантирую, что оценки в reduceLeft
(что я считаю более подходящим чем foldLeft
здесь) происходит только по мере необходимости!
def correct(word:String) = {
Stream(known(Set(word)) _,
known(edits1(word)) _,
known_edits2(word) _,
Set(word) _
).find( !_().isEmpty ) match {
case Some(candidates) =>
candidates.reduceLeft {(res, n) => if (NWORDS(res) > NWORDS(n)) res else n}
case _ => "" //or some other value
}
Я, вероятно, допустил здесь некоторые синтаксические ошибки, но я думаю, что подход Stream
является допустимым
Я не уверен, почему вы пытаетесь использовать ленивую оценку для , известного
, а не просто использовать поток, как показано на примере oxbow_lakes. Лучший способ сделать то, что он сделал:
def correct(word: String) = {
import Stream._
val str = cons(known(Set(word)),
cons(known(edits1(word)),
cons(known_edits2(word),
cons(Set(word), empty))))
str find { !_.isEmpty } match {
case Some(candidates) =>
candidates.foldLeft(Set[String]()) { (res, n) =>
if (NWORDS(res) > NWORDS(n)) res else n
}
case None => Set()
}
}
Эксплуатация того факта, что Stream.cons
уже ленивый, поэтому нам не нужно оборачивать все в thunk.
If you ' мы действительно настроены на хороший синтаксис, мы можем добавить немного синтаксического сахара ко всем этим недостаткам:
implicit def streamSyntax[A](tail: =>Stream[A]) = new {
def #::(hd: A) = Stream.cons(hd, tail)
}
Теперь наше ранее некрасивое str
определение сводится к следующему:
def correct(word: String) = {
val str = known(Set(word)) #:: known(edits1(word)) #::
known_edits2(word) #:: Set(word) #:: Stream.empty
...
}
Готовность к Scala 2.7 (включая неявный обход производительности):
class Or[A](one: Set[A]) {
def or(other: => Set[A]): Set[A] = if (one.isEmpty) other else one
}
implicit def toOr[A](one: Set[A]) = new Or(one)
def correct(word: String) = {
candidates = known(Set(word)) or known(edits1(word)) or known_edits2(word) or Set(word)
candidates.foldLeft("") {(a, b) => if (NWORDS(a) > NWORDS(b)) a else b}
}
Качество Scala 2.8:
implicit def toOr[A](one: Set[A]) = new AnyRef {
def or(other: => Set[A]): Set[A] = if (one.isEmpty) other else one
}
def correct(word: String) = {
candidates = known(Set(word)) or known(edits1(word)) or known_edits2(word) or Set(word)
candidates.max(Ordering.fromLessThan[String](NWORDS(_) < NWORDS(_)))
}
Тем не менее, я в значительной степени поддержал всех остальных. Я не рассматривал Stream
.
EDIT
Кажется, Ordering.fromLessThan
может привести к двойному количеству необходимых сравнений. Вот альтернативная версия для этой строки:
candidates.max(new Ordering[String] { def compare(x: String, y: String) = NWORDS(x) - NWORDS(y) })
Я пытался реализовать короткую реализацию Scala корректора орфографии. Это 15 строк без импорта. Самая короткая замена для Python's или простой вызов по имени параметра:
def or[T](candidates : Seq[T], other : => Seq[T]) = if(candidates.isEmpty) other else candidates
def candidates(word: String) = or(known(List(word)), or(known(edits1(word)), known(edits2(word))))
В реальном мире я бы использовал неявное преобразование, предложенное Даниилом
.