为什么单个阿拉伯字符在样式化时表现为独立字符?

16

我想要实现的基本上是阿拉伯字符误用高亮器!

为了更容易理解,我将尝试解释一个类似于英语的功能。

想象一下一个大小写错误的字符串,需要将其正确地重写,所以用户在输入框中重新输入字符串并提交后,js会检查是否有任何字符未被更正,然后显示整个字符串,并在红色中突出显示那些字母;

例如 [test] 变成 [Test]

为此,我正在检查这些字符,如果检测到故障字符,则将其包围在 span 中以便以红色着色。

到目前为止,一切都很好,但是当我尝试为阿拉伯语复制此操作时,故障字符会从单词中分离出来,使其无法阅读。


演示: jsfiddle

function check1() {
  englishanswer.innerHTML = englishWord.value.replace(/t/, '<span style="color:red">T</span>');
}

function check2() {
  arabicanswer.innerHTML =
    arabicWord.value.replace(/\u0647/, '<span style="color:red">' +
      unescape("%u0629") + '</span>') +
    '<br>' + arabicWord.value.replace(/\u0647/, unescape('%u0629'));
}
fieldset {
  border: 2px groove threedface;
  border-image: initial;
  width: 75%;
}
input {
  padding: 5px;
  margin: 5px;
  font-size: 1.25em;
}
p {
  padding: 5px;
  font-size: 2em;
}
<fieldset>
  <legend>English:</legend>
  <input id='englishWord' value='test' />
  <input type='submit' value='Check' onclick='check1()' />
  <p id='englishanswer'></p>
</fieldset>

<fieldset style="direction:rtl">
  <legend>عربي</legend>
  <input id='arabicWord' value='بطله' />
  <input type='submit' value='Check' onclick='check2()' />
  <p id='arabicanswer'></p>
</fieldset>

注意在测试阿拉伯语单词时,带有跨度的字符 [第一预览] 与单词的其余部分分开显示,而没有带有跨度的字符 [第二预览] 则正常显示。


编辑:问题的预览[Chrome UA]

enter image description here


2
没错,只在Chrome中发生。在IE,FF,OP和AS中没有发生。 - Jawad
@Jawad,在Safari 6中确实会发生这种情况。 - katspaugh
3
我知道壁虎会竭尽全力让事情像用户所期望的那样工作,例如,涂色一个复合字母中的一个字母不会导致它被分成单个字母。我只能假设Webkit没有这么聪明。 - Neil
它必须是针对WebKit的。我只能假设有一个开放的错误报告。 - nneonneo
2
找到了错误报告:https://bugs.webkit.org/show_bug.cgi?id=6148。看起来有人正在积极处理,这是个好消息。不幸的是,在我的 Safari 中,第 16 条评论中提到的 &zwj; 技巧不起作用。 - nneonneo
显示剩余5条评论
6个回答

3
这是 WebKit 浏览器(Chrome、Safari)长期存在的一个 bug:HTML 标记会破坏拼接行为。以往,显式使用零宽连接符 (ZWJ) 可以解决问题(请参见问题 Partially colored Arabic word in HTML),但现在看来这个 bug 变得更加严重。
作为笨拙但可能是唯一的解决方法,您可以使用阿拉伯字母的上下文形式。可以先使用静态 HTML 标记和 CSS 进行测试,例如:
بطﻠ<span style="color:red">ﺔ</span>

我在span元素中使用ﺔ U+FE94 阿拉伯字母TEH MARBUTA FINAL FORM,而不是普通的U+0629阿拉伯字母TEH MARBUTA,以及ﻠ U+FEE0 ARABIC LETTER LAM MEDIAL FORM而不是U+0644阿拉伯字母LAM。

要在JavaScript中实现此操作,需要在插入带有阿拉伯字母的标记时,根据其在单词中的位置将断点(由标记引起)前后的字符更改为初始、中间或最终表示形式。


2
我知道我提供的解决方案并不是很优雅,但它可以工作。请告诉我你的想法:
<script>
    function check1(){
    englishanswer.innerHTML = englishWord.value.replace(/t/,'<span style="color:red">T</span>');
}
function check2(){
arabicanswer.innerHTML = 
    arabicWord.value.replace(/\u0647/,'<span style="color:red">'+
    unescape("%u0640%u0629")+'</span>')+
    '<br>'+arabicWord.value.replace(/\u0647/,unescape('%u0629'));
}
</script>

<fieldset>
<legend>English:</legend>
<input id='englishWord' value='test'/>
<input type='submit' value='Check' onclick='check1()'/>
<p id='englishanswer'></p>
</fieldset>

<fieldset style="direction:rtl">
<legend>عربي</legend>
<input id='arabicWord' value='بطلـه'/>
<input type='submit' value='Check' onclick='check2()'/>
<p id='arabicanswer'></p>
</fieldset>

它改变了单词的外观...这可能是不可取的。 - nneonneo
我知道,但我没有找到一个好的解决方案来解决他的问题,我只是使用字母“u0640”作为两个分离字母之间的链接。 - Rachid O
是的,我知道。我认为如果浏览器没有修复,这个问题不会轻易解决。你的解决方案是目前为止最好的。我想点赞,但我今天已经没有更多的投票了 :'( - nneonneo
目前最佳解决方案,但我们需要像Mohsen Afshin在这里提到的那样计算字符位置[https://dev59.com/qWcs5IYBdhLWcg3wYzH6#12887003]。 - Mohammed Ibrahim

1

正如Jukka K. Korpela所指出的,这主要是大多数基于WebKit的浏览器(chrome、safari等)中的一个错误。

除了使用类似TAMDEED字符或获取阿拉伯字母的上下文形式之外,还有一个简单的技巧可以将字母作为单个阿拉伯连字符处理——在你想要处理的字母之前/之后加上零宽连接器&zwj;&#x200d;)。例如:

<p>عرب&#x200d;<span style="color: Red;">&#x200d;ي</span></p>  

演示:jsfiddle
还请参阅 Webkit bug 报告。


无需解决方案,因为它已经在Chrome 76中使用新的布局引擎进行修复。请参考以下链接:https://developers.google.com/web/updates/2019/06/layoutNG - husayt

1

在处理字符时,您应该注意开头、中间、结尾和孤立字符。完整列表可在此处找到。

使用ufe94代替u0629

arabicWord.value.replace(/\u0647/,'<span style="color:red">'+ unescape("%ufe94")+'</span>')+

这是标准字符Unicode,可能Safari无法正确解释它。我已在Chrome中进行了测试并且可以正常工作。 - Mohsen Afshin

0

不要使用span,而是使用HTML5 ruby元素,并添加阿拉伯语tatweel字符“ـ”(U+0640),你知道这个可以扩展字母的字符(shift+j)。

因此,您的代码变成:

arabicanswer.innerHTML = 
        (arabicWord.value).replace(/\u0647/,'ـ<ruby style="color:red"> ـ'+
        unescape("%u0629")+'</ruby>')+
        '<br>'+arabicWord.value.replace(/\u0647/,unescape('%u0629'));
    }

这里是更新后的代码片段:http://jsfiddle.net/fjz5C/28/


遗憾的是,在Safari 6中似乎无法正常运行。 - nneonneo

0

我建议在字符前后添加连字号/托威尔符号。虽然这并不能真正解决问题,但它会使问题难以被察觉,因为它会强制将lam转换成中央形式,而将taa marbuta转换成最终形式。如果这样做有效的话,那么相比于实际上将字母转换为它们的中央或最终形式,这种方法会更加灵活。

不过,你好像还有其他问题。我去了你的网站,并输入了一个hadha的拼写错误,只是想看看它会发生什么,结果两个单词中的ha都断开了,如果唯一的问题是格式标签,这是没有道理的。(我使用的是Mac上的Firefox浏览器。)

enter image description here

祝你好运!


虽然使用tatweel字符即“ـ”可以解决给定的情况,但它无法解决分离字符的一般问题,“这是UA相关问题”(我只是用给定的示例说明问题,但在应用程序中,除非我确定字符位置,否则我将无法确定是否应该使用tatweel或不使用tatweel,即使用正则表达式或其他方法确定字符位置后,使用tatweel或使用适当的字符并没有区别;至少我是这么认为的)。 - Mohammed Ibrahim
至于你的第二点,代码确实正确地替换了字符,但在阿拉伯语中没有以“Tāʾ marbūṭa”即“ة”开头的单词,因此它没有初始形式,而另一方面,“hāʾ”即“ه”有初始形式,这是你在输入字段中使用的。顺便说一下,你拼写了“هاذا”这个词 :) - Mohammed Ibrahim

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接