8

I am trying to add a span tag around Hebrew and English sentence in a paragraph. E.g. "so היי all whats up אתכם?" will become :

[span]so[/span][span]היי[/span][span]all whats up[/span][span]אתכם[/span]

I have been trying with regexp but its just removing the Hebrew words and joining the English words in one span.

var str = 'so היי all whats up אתכם?'
var match= str.match(/(\b[a-z]+\b)/ig);
var replace = match.join().replace(match.join(),'<span>'+match.join()+'</span>')
Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
roude
  • 89
  • 3
  • 1
    Your regex seems wrong, it doesn't contain any Hebrew matches, just [a-z]+ which is, of course English – Ishay Peled Jul 03 '15 at 08:39
  • so how to do it right? – roude Jul 03 '15 at 08:40
  • 3
    You can try adding the Hebrew range: [\u0590-\u05FF] to your regex, this is א-ת in unicode – Ishay Peled Jul 03 '15 at 08:43
  • (match.join(),''+match.join()+''') // maybe something like this, with a check that it isn't the last of first word in a sentence in order to apply the tags right? Just an idea. Not very pretty. – NachoDawg Jul 03 '15 at 08:43
  • is `[ה-א]+` a thing in js-utf-8-regex ? if not search for those `\uFFA3` utf-8 regex stuff all over SO. you'll probably need to search for a utf-8 char range explicitly – birdspider Jul 03 '15 at 08:44
  • Well nothing helped so far – roude Jul 03 '15 at 09:01
  • It's not clear what Hebrew character you want. Alef to Taf? Do you want wide Hebrew character, Hebrew ligatures or Hebrew punctuations? – nhahtdh Jul 03 '15 at 09:03
  • yeh..alef to taf in hebrew and a to z in english ,thanks – roude Jul 03 '15 at 09:08
  • 2
    This question [has been raised on Meta](http://meta.stackoverflow.com/q/298491/472495). – halfer Jul 03 '15 at 09:36

3 Answers3

9

Previous answers here did not account for the whole word requirement. Indeed, it is difficult to achieve this since \b word boundary does not support word boundaries with neighboring Hebrew Unicode symbols that we can only match with a character class using \u notation.

I suggest using look-aheads and capturing groups to make sure we capture the whole Hebrew word ((^|[^\u0590-\u05FF])([\u0590-\u05FF]+)(?![\u0590-\u05FF]) that makes sure there is a non-Hebrew symbol or start of string before a Hebrew word - add a \s if there are spaces between the Hebrew words!), and \b[a-z\s]+\b to match sequence of whole English words separated with spaces.

If you plan to insert the <span> tags into a sentence around whole words, here is a function that may help:

var str = 'so היי all whats up אתכם?';
//var str = 'so, היי, all whats up אתכם?';
var result = str.replace(/\s*(\b[a-z\s]+\b)\s*/ig, '<span>$1</span>');
result = result.replace(/(^|[^\u0590-\u05FF])([\u0590-\u05FF]+)(?![\u0590-\u05FF])/g, '$1<span>$2</span>');
document.getElementById("r").innerHTML = result;
span {
    background:#FFCCCC;
    border:1px solid #0000FF;
}
<div width="645" id="r"/>

Result:

<span>so</span><span>היי</span><span>all whats up</span><span>אתכם</span>?

If you do not need any punctuation or alphanumeric entities in your output, just concatenated whole English and Hebrew words, then use

var str = 'היי, User234, so 222היי all whats up אתכם?';
var re = /(^|[^\u0590-\u05FF])([\u0590-\u05FF]+)(?![\u0590-\u05FF])|(\b[a-z\s]+\b)/ig;
var res = [];
while ((m = re.exec(str)) !== null) {
    if (m.index === re.lastIndex) {
        re.lastIndex++;
    }
  if (m[1] !== undefined) {
      res.push('<span>'+m[2].trim()+'</span>');
    }
  else
    {
      res.push('<span>'+m[3].trim()+'</span>');
    }
  
}
document.getElementById("r").innerHTML = res.join("");
span {
    background:#FFCCCC;
    border:1px solid #0000FF;
}
<div width="645" id="r"/>

Result:

<span>היי</span><span>so</span><span>היי</span><span>all whats up</span><span>אתכם</span>
Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
  • I think to fully emulate word boundary behavior the negated Hebrew character class can be extended to also not match digits and an underscore: `(^|[^\u0590-\u05FF0-9_])([\u0590-\u05FF]+)`. Does my solution work for you? – Wiktor Stribiżew Jul 06 '15 at 14:42
1

I think the Regex you want is something like [^a-z^\u0591-\u05F4^\s]. I'm not entirely sure how you want to handle spaces.

My solution

Copy str to a new var res, replacing any characters that aren't A-Z / Hebrew.
Loop over any english (a-z) characters in str and wrap them in a span, using res.replace.
Do the same again for the Hebrew characters.

It's not quite 100%, but seems to work well enough IMO.

var str = 'so היי all whats up אתכם?';
var finalStr = str.replace(/([^a-z^\u0591-\u05F4^\s])/gi, '');

var rgx = /([a-z ]+)/gi;
var mat = str.match(rgx);

for(var i=0; i < mat.length; ++i){
    var match = mat[i];
    finalStr = finalStr.replace(match.trim(),'<span>'+match.trim()+'</span>');
}

rgx = /([\u0591-\u05F4 ]+)/gi;
var mat = str.match(rgx);

for(var i=0; i < mat.length; ++i){
    var match = mat[i];
    finalStr = finalStr.replace(match.trim(),'<span>'+match.trim()+'</span>');
}

document.getElementById('res').innerHTML = finalStr;

http://jsfiddle.net/daveSalomon/0ns6nuxy/1/

Dave Salomon
  • 3,287
  • 1
  • 17
  • 29
  • Thanks dave ,your solution works great but it also creating empty spans – roude Jul 03 '15 at 09:59
  • Yeah, I think my regex might be a little off. You could always check `match.trim()` before adjusting the finalStr. e.g. http://jsfiddle.net/daveSalomon/0ns6nuxy/2/ – Dave Salomon Jul 03 '15 at 10:11
0

Judging by this post you can try something like this: ((?:\s*\w+)+|(?:\s*[\u0590-\u05FF]+)+?(?=\s?[A-Za-z0-9!?.])) https://regex101.com/r/kA3yV5/4

You may need to edit it for your particular cases (for example, if some non-word characters start to appear), but it does the trick. It tries to match words and form sentences from English character list, if it doesn't work, it tries to make words/sentences out of Hebrew character list, until an english character is spotted again.

It's not perfect yet, as you may want to add other punctuation characters and there's some spaces you don't want in the 1st position (because javascript doesn't support lookbehinds, I didn't figure out a good way to remove them on the spot, but they can be at position 1 and removed from string)

Community
  • 1
  • 1
Andris Leduskrasts
  • 1,210
  • 7
  • 16