Tüm "\" Değiştir

6 Cevap php

İlk şeyler ilk: Ne this, this, this, ne this sorumu yanıtladı. Yani bir yenisini açacağım.

Please read

Tamam, tamam. I know regexes genel HTML ayrıştırmak için bir yol olmadığını. Oluşturulan belgeler sınırlı, kontrollü bir HTML alt kümesi kullanılarak yazılır Unutmayınız. Ve dokümanlar yazma insanlar ne yaptığınızı biliyorum. Onlar tüm BT uzmanları vardır!

Kontrollü sözdizimi is mümkün belgeleri ayrıştırmak Verilen ben burada Regexes kullanarak var.

Ben web keyfi belgeleri indirmek ve onları ayrıştırmak çalışıyorum değilim!

Ve eğer does belge düzenlenmiş olması, başarısız, bu nedenle ayrıştırmak olacak ayrıştırma. Ben burada sesleniyorum sorunu (yani diğer iki desenleri içinde desenleri yerini) bundan daha geneldir.

A little bit of background (you can skip this...)

Bizim ofiste bizim belgeleri "güzel yazdırmak" gerekiyor. Bu nedenle neden bazı Word belgeleri içine koyarak geldi. Şimdiye kadar oldukça henüz minnetle değiliz. Ben bu halletmek Ve eğer biz gerek olmayabilir.

The current state (... and this)

Docs ana parçası, bir TikiWiki veritabanında saklanır. Ben PDF (LaTeX ile) HTML belgeleri dönüştürür aptal PHP komut dosyası oluşturduk. Seçilen Wiki-Sistemi must have özelliklerinden biri WYSIWYG editörü oldu. Hangi, beklendiği gibi resmi DOM sonra daha az olan belgeler bize bırakır.

Sonuç olarak, ben "basit" Regexes kullanarak belgeyi transliterating ediyorum. Hepsi şimdiye kadar işleri (çoğunlukla) ince, ama ben henüz kendi başıma çözemedim bir sorunla karşılaştı.

The problem

Bazı özel karakterler LaTeX biçimlendirme yerini gerekir. Exaple için, \ karakter $\backslash$ (birisi, başka bir çözüm bilen sürece?) Tarafından değiştirilmesi gerekir.

Except a verbatim bloke ederken!

I-verbatim bölümleri ile <code> etiketler yerine yok. Bu code blok backslash'lar (Windows klasör adları için olduğu gibi) içeriyorsa, ancak, komut hala bu backslash'lar değiştirir.

Ben negatif geriye ilerleme ve / veya LookAheads kullanarak bu çözebilir herhalde. Ama benim girişimleri işe yaramadı.

Verilen, gerçek bir çözümleyici ile daha iyi olurdu. Aslında, benim "in-beyin-yol haritası" üzerinde bir şeydir, ama currently kapsamı dışındadır. Komut bizim sınırlı bilgi alanı için yeterince iyi çalışıyor. Bir ayrıştırıcı oluşturma bana sıfırdan hemen hemen başlamak için gerektirir.

My attempt

Example Input

The Hello \ World document is located in:
<code>C:\documents\hello_world.txt</code>

Expected output

The Hello $\backslash$ World document is located in:
\begin{verbatim}C:\documents\hello_world.txt\end{verbatim}

Bu şimdiye kadar ile gelebilir en iyisi:

<?php
$patterns = array(
    "special_chars2" => array( '/(?<!<code[^>]*>.*)\\\\[^$](?!.*<\/code>)/U', '$\\backslash$'),
);

foreach( $patterns as $name => $p ){
    $tex_input = preg_replace( $p[0], $p[1], $tex_input );
}
?>

Bu sadece bir alıntıdır, ve [^$] başka bir LaTeX gereksinimi olduğunu unutmayın.

Başka bir girişimi olan seemed çalışmak için:

<?php
$patterns = array(
    "special_chars2" => array( '/\\\\[^$](?!.*<\/code>)/U', '$\\backslash$'),
);

foreach( $patterns as $name => $p ){
    $tex_input = preg_replace( $p[0], $p[1], $tex_input );
}
?>

... Diğer bir deyişle: Negatif Geriye İlerleme dışarıda bırakarak.

Ama bu daha fazla hata eğilimli Geriye bakan ve ileri yönlü hem de daha görünüyor.

A related question

Sizin de fark etmiş olabileceğiniz gibi, desen ungreedy olan (/.../U). Bir <code> bloğunun içine Yani bu maç sadece az mümkün olacak? Göz-arounds göz önüne alındığında?

6 Cevap

Bana, ben HTML ayrıştırıcı bulmaya çalışacağız ve bu ile yapacak.

Başka bir seçenek <code>.*?</code> ve other parts içine dize öbek çalışacağız olduğunu.

ve diğer parçaları güncelleyecek ve onu tekrar birleşecek.

$x="The Hello \ World document is located in:\n<br>
<code>C:\documents\hello_world.txt</code>";

$r=preg_split("/(<code>.*?<\/code>)/", $x,-1,PREG_SPLIT_DELIM_CAPTURE);

for($i=0;$i<count($r);$i+=2)
    $r[$i]=str_replace("\\","$\\backslash$",$r[$i]);

$x=implode($r);

echo $x;

İşte sonuç olduğunu.

The Hello $\backslash$ World document is located in: 
C:\documents\hello_world.txt

Üzgünüm, benim yaklaşım sizin için uygun değilse.

Ben negatif geriye ilerleme ve / veya LookAheads kullanarak bu çözebilir herhalde.

Yanlış saymak. Regular expressions are not a replacement for a parser.

Sana boru htmltidy aracılığıyla html, daha sonra bir dom-çözümleyici ile okumak ve sonra da hedef çıkış biçimine dönüştürmek dom öneririz. Bu rota alarak sizin engelleyen bir şey var mı?

Ayrıştırıcı FTW, tamam. Eğer bir ayrıştırıcı kullanamazsınız Ama eğer, and Eğer <code> etiketleri iç içe asla emin olabilirsiniz, size şunu deneyebilirsiniz:

  1. Dosyanızın <code>.*?</code> bölümleri bulun (muhtemelen nokta maçlar-newlines modunu açmak gerekir).
  2. #?#?#?# gibi benzersiz bir şey ile bu bölümün içindeki tüm backslash'lar değiştirin
  3. Yeni bölümü ile 1 bulundu bölümünü değiştirin
  4. $\backslash$ ile tüm backslash'lar değiştirin
  5. Als <code> \begin{verbatim} ile ve </code> \end{verbatim} ile değiştirin
  6. Yerine #?#?#?# ile \

Bilginize, PHP regexes değişken uzunlukta Geriye İlerleme desteklemez. Yani iki sınırları arasındaki bu koşullu eşleştirme zorlaştırır.

Pandoc? Pandoc biçimleri bir grup arasında dönüştürür. bunları da gizli sonra birlikte sinekler bir demet arada kullanabilirsiniz. Belki php ile birlikte bir kaç kabuk komut komut kazıma?

Lütfen "beklenen girdi" ve komutu ile pandoc -o text.tex test.html çıktı:

The Hello \textbackslash{} World document is located in:
\verb!C:\documents\hello_world.txt!

Pandoc, standart girdiden okunur doğru bir dosya içine stdout veya boru yazabilirsiniz.

Lütfen <code> blokları iç içe olmamak şartıyla, bu regex sonra bir ters eğik bulur ^ in-dize-başlatmak veya </code> ile hiçbir {[(0)] } arasında.

((?:^|</code>)(?:(?!<code>).)+?)\\
    |            |              |
    |            |              \-- backslash
    |            \-- least amount of anything not followed by <code>
    \-- start-of-string or </code>

Ve ile değiştirin:

$1$\backslash$

Siz "SingleLine" modunda bu regex çalıştırmak zorunda, bu yüzden . satırsonlarını eşleşir ediyorum. Ayrıca bunu birden fazla kez çalıştırmak gerekiyor, küresel değiştirme belirterek yeterli değildir. Her yedek sadece start-of-string ya da </code> sonra ilk uygun ters eğik çizgi yerini alacak.

DOMDocument gibi bir HTML veya XML parser dayalı bir ayrıştırıcı yazın. Ayrıştırılır DOM travers ve \ $\backslash$ ile bir code düğüm ve bir {[her düğümün soyundan değil her metin düğümünün üzerine (yerine 2)]} düğüm \begin{verbatim} … \end{verbatim}.