在 XeLaTeX 中仅使用拉丁字符书写希腊语

在 XeLaTeX 中仅使用拉丁字符书写希腊语

在 LaTeX 中,可以使用命令生成希腊语表达式 Ἑλληνικὴ γλώσσα

\textgreek{<Ellhnik`h gl'wssa}

即,在 TeX 文件中仅使用拉丁字符,而不必使用任何希腊字母。

此特定命令在 XeLaTeX 中不起作用。

有没有办法在 XeLaTeX 中将拉丁字符转换为希腊字符?

我不是说必须写类似的东西

 $\gamma\lambda\'\omega\sigma\sigma\alpha$.

答案1

由于这个问题与 XeTeX 有关,我认为您的文档可以毫不费力地迁移到 LuaTeX。首先,我必须说我知道没有什么关于希腊语,但至少根据 Davislor 在评论中分享的文件,我了解了一点需要做的事情。我想到的解决方案如下所示。

  1. 目前,\textgreek仅支持文本,这意味着几乎没有 LaTeX 命令可以在里面正常工作。
  2. L2G_VARIANT_GRAVE我只定义了、L2G_VARIANT_ROUGH和的字符映射。您必须在表L2G_VARIANT_ACUTE中填写新的映射。_l2g_variant_indicator
\documentclass{exam}
\usepackage{fontspec}
\usepackage{luacode}
\usepackage{expl3}

\setmainfont{DejaVu Serif}

\begin{luacode*}
L2G_VARIANT_ACUTE = 0x00000001
L2G_VARIANT_CIRCUM = 0x00000002
L2G_VARIANT_DIA = 0x00000004
L2G_VARIANT_DIACIRCUM = 0x00000008
L2G_VARIANT_DIAGRAVE = 0x00000010
L2G_VARIANT_GRAVE = 0x00000020
L2G_VARIANT_IOTASUB = 0x00000040
L2G_VARIANT_ROUGH = 0x00000080
L2G_VARIANT_SMOOTH = 0x00000100

l2g_variants = {
  "acute", "circum", "dia", "diacircum", "diagrave", "grave", "iotasub", "rough", "smooth"
}

l2g_char_mapping = {
  [97]=945,[98]=946,[99]=958,[100]=948,[101]=949,[102]=966,
  [103]=947,[104]=951,[105]=953,[107]=954,[108]=955,[109]=956,
  [110]=957,[111]=959,[112]=960,[113]=952,[114]=961,[116]=964,
  [117]=965,[118]=989,[119]=969,[120]=958,[121]=968,[122]=950,
  [65]=913,[66]=914,[67]=926,[68]=916,[69]=917,[70]=934,
  [71]=915,[72]=919,[73]=921,[75]=922,[76]=923,[77]=924,
  [78]=925,[79]=927,[80]=928,[81]=920,[82]=929,[84]=932,
  [85]=933,[86]=988,[87]=937,[88]=926,[89]=936,[90]=918
}

_l2g_variant_indicator = {
  ["`"] = L2G_VARIANT_GRAVE,
  ["<"] = L2G_VARIANT_ROUGH,
  ["'"] = L2G_VARIANT_ACUTE
}

-- an integer version of _l2g_variant_indicator will be generated right away
l2g_variant_indicator = {}
for key, val in pairs(_l2g_variant_indicator) do
  local ind = key:byte(1)
  l2g_variant_indicator[ind] = val
end

l2g_variant_mapping = {
  [97]={[256]=7936,[288]=7938,[352]=8066,[128]=7937,[160]=7939,[224]=8067,[257]=7940,[321]=8068,[129]=7941,[193]=8069,[258]=7942,[322]=8070,[130]=7943,[194]=8071,[320]=8064,[192]=8065,[32]=8048,[96]=8114,[1]=940,[65]=8116,[2]=8118,[66]=8119,[64]=8115},
  [65]={[256]=7944,[288]=7946,[352]=8074,[128]=7945,[160]=7947,[224]=8075,[257]=7948,[321]=8076,[129]=7949,[193]=8077,[258]=7950,[322]=8078,[130]=7951,[194]=8079,[320]=8072,[192]=8073,[1]=902,[32]=8122,[64]=8124},
  [104]={[256]=7968,[288]=7970,[352]=8082,[128]=7969,[160]=7971,[224]=8083,[257]=7972,[321]=8084,[129]=7973,[193]=8085,[258]=7974,[322]=8086,[320]=8080,[192]=8081,[1]=942,[65]=8132,[2]=8134,[66]=8135,[32]=8052,[64]=8131},
  [72]={[256]=7976,[288]=7978,[352]=8090,[128]=7977,[160]=7979,[224]=8091,[257]=7980,[321]=8092,[129]=7981,[193]=8093,[258]=7982,[322]=8094,[320]=8088,[192]=8089,[1]=905,[32]=8138,[64]=8140},
  [119]={[256]=8032,[288]=8034,[352]=8098,[128]=8097,[160]=8035,[224]=8099,[257]=8036,[321]=8100,[129]=8037,[193]=8101,[258]=8038,[322]=8102,[130]=8039,[194]=8103,[320]=8096,[192]=8097,[32]=8060,[96]=8178,[1]=974,[65]=8180,[2]=8182,[66]=8183,[64]=8179},
  [87]={[256]=8040,[288]=8042,[352]=8106,[128]=8041,[160]=8043,[224]=8107,[257]=8044,[321]=8108,[129]=8045,[193]=8109,[258]=8046,[322]=8110,[130]=8047,[194]=8111,[320]=8104,[192]=8105,[1]=911,[32]=8186,[64]=8188},
  [105]={[4]=970,[5]=912,[256]=7984,[288]=7986,[128]=7985,[160]=7987,[257]=7988,[129]=7989,[258]=7990,[130]=7991,[36]=8146,[16]=8146,[6]=8151,[8]=8151,[1]=943,[32]=8054,[2]=8150},
  [117]={[4]=971,[5]=944,[256]=8016,[288]=8018,[128]=8017,[160]=8019,[257]=8020,[129]=8021,[258]=8022,[130]=8023,[36]=8162,[16]=8162,[6]=8167,[8]=8167,[1]=973,[32]=8058,[2]=8166},
  [101]={[256]=7952,[288]=7954,[128]=7953,[160]=7955,[257]=7956,[129]=7957,[1]=941,[32]=8050},
  [69]={[256]=7960,[288]=7962,[128]=7961,[160]=7963,[257]=7964,[129]=7965,[1]=904,[32]=8136},
  [73]={[256]=7992,[288]=7994,[128]=7993,[160]=7995,[257]=7996,[129]=7997,[258]=7998,[130]=7999,[1]=906,[4]=938,[32]=8154},
  [111]={[256]=8000,[288]=8002,[128]=8001,[160]=8003,[257]=8004,[129]=8005,[1]=972,[32]=8056},
  [79]={[256]=8008,[288]=8010,[128]=8009,[160]=8011,[257]=8012,[129]=8013,[1]=908,[32]=8184},
  [85]={[128]=8017,[160]=8027,[129]=8029,[130]=8031,[1]=910,[4]=939,[32]=8170},
  [114]={[256]=8164,[128]=8165},
  [82]={[128]=8172}
}

-- assume Lua 5.3 is used, otherwise may need to use bit32 library
-- https://stackoverflow.com/questions/5977654/how-do-i-use-the-bitwise-operator-xor-in-lua
function l2g_bitwise_or(a, b)
  return a | b
end

function l2g_print_warning(s)
  tex.print(string.format([[\PackageWarning{l2g}{%s}]], s))
end

function l2g_code_to_char(c)
  return utf8.char(c)
end

l2gstate = {
  ["variant_flag"] = 0,
  ["variant_storage"] = -1,
  ["result"] = -1
}


function l2gstate:new()
  local obj = {}
  setmetatable(obj, self)
  self.__index = self
  self.result = {}
  self.variant_storage = {}
  return obj
end

function l2gstate:get_last_variant()
  local len = #self.variant_storage
  if len == 0 then
    return -1
  end
  local last_char = self.variant_storage[len]
  return utf8.codepoint(last_char)
end

function l2gstate:register_variant(var_ccode)
  local var_flag = l2g_variant_indicator[var_ccode]
  self.variant_flag = l2g_bitwise_or(self.variant_flag, var_flag)
  table.insert(self.variant_storage, l2g_code_to_char(var_ccode))
end

function l2gstate:discard_variant()
  self.variant_flag = 0
  self.variant_storage = {}
end

function l2gstate:add_variant_char()
  for _, val in ipairs(self.variant_storage) do
    table.insert(self.result, val)
  end
end

function l2gstate:add_char(code)
  table.insert(self.result, l2g_code_to_char(code))
end


function l2g(s)
  local pos = 1
  local cur_byte = -1
  local cur_char = nil
  
  local variant_state = l2gstate:new()
  local char_find = nil
  local inner_find = nil
  local inner_char_find = nil
  
  while pos <= utf8.len(s) do
    cur_byte = utf8.codepoint(s, pos)
    cur_char = utf8.char(cur_byte)
    
    variant_find = l2g_variant_indicator[cur_byte]
    if variant_find ~= nil then
      if cur_byte == variant_state:get_last_variant() then
        -- escaping current sequence
        variant_state:add_char(cur_byte)
        variant_state:discard_variant()
      else
        variant_state:register_variant(cur_byte)
      end
      goto continue
    end
    
    char_find = l2g_char_mapping[cur_byte]
    if char_find ~= nil then
      -- try to resolve variants
      if variant_state.variant_flag > 0 then
        inner_find = l2g_variant_mapping[cur_byte]
        if inner_find ~= nil then
          inner_char_find = inner_find[variant_state.variant_flag]
          if inner_char_find ~= nil then
            variant_state:add_char(inner_char_find)
          else
            l2g_print_warning(string.format("letter '%s' does not have variant type %d", cur_char, variant_state.variant_flag))
            variant_state:add_variant_char()
            variant_state:add_char(cur_byte)
          end
        else
          l2g_print_warning(string.format("letter '%s' does not have any variant", cur_char))
          variant_state:add_variant_char()
          variant_state:add_char(cur_byte)
        end
        variant_state:discard_variant()
      else
        -- no variant set for this character
        variant_state:add_char(char_find)
      end
    else
      -- unable to find this character in mapping
      variant_state:add_variant_char()
      variant_state:add_char(cur_byte)
      variant_state:discard_variant()
    end
    
    ::continue::
    pos = pos + 1
  end

  if variant_state:get_last_variant() ~= -1 then
    variant_state:add_variant_char()
    variant_state:discard_variant()
  end

  return table.concat(variant_state.result, "")
end
\end{luacode*}

\newcommand{\textgreek}[1]{
  \directlua{
    local res = l2g("\luaescapestring{#1}")
    tex.print(res)
  }
}


\begin{document}
\par \textgreek{<Ellhnik`h gl'wssa}
\par \textgreek{<Ellhnik<`h gl<'wssa}
\par \textgreek{<<Ellhnik``h gl''wssa}

\end{document}

结果是:

Ἑλληνικὴ γλώssα
Ἑλληνικἣ γλὥssα
<Ελληνικ‘η γλ’ωssα

答案2

虽然你没有提供完整的 MWE,但看起来你正在使用teubner包,直接或间接通过babel。这与 beta 代码或直接映射到 LGR 不同。

最好转换您的源

我的第一个建议是,如果可行的话,将输入转换为 Unicode,这样您就可以使用通常用于希腊语的任何输入法进行搜索、复制、粘贴、拼写检查、编辑等。如果是多音调希腊语,尤其如此,因为无重音希腊字母与其拉丁音译的映射就会中断。

使用外部脚本解析 LaTeX 源并生成新的 UTF-8 源文件有多困难取决于表达式的复杂程度\textgreek。如果它们都像您的示例一样,则可以用正则表达式来完成。如果它们只能包含行为良好的非嵌套命令(例如)\textbf{<Ellhnik`h},则仍然可以机械地执行而无需编写更复杂的解析器。如果您的输入可以包含任意嵌套的命令,那么您至少需要编写一个可以匹配括号的解析器,如果命令可以执行诸如更改语言之类的复杂操作,则需要扫描该操作。如果您将以编程方式生成的字符串传递给\textgreek,则需要手动重写它。

请注意,自 2020 年起,XeTeX 和 LuaTeX 仅支持预组合 (NFC) 希腊字符,不支持组合希腊重音符号。软件包维护人员告诉我,语言babel文件可能会在 Unicode 连字算法之前修复此问题。

在 XeTeX 中

可以编写一个.tec映射文件,将 Teubner 代码转换为 Unicode,类似于我为测试版代码编写的那个。 您可以用 来编译它,然后使用 的字体功能teckit_compile来激活它。Mapping=fontspec

除其他差异外,Teubner 代码可以包含诸如 之类的 LICR 宏\~{e},这些宏将生成组合重音符号,并且必须将这些宏规范化为 NFC 形式才能正常工作。

在 LuaTeX 中

Alan Xiang 提出了一个使用 Lua 的答案,但我还没有测试过。

作为后备方案

作为最后的手段,可以使用 加载 LGR 字体luainputenc。也许可以继续加载teubner那些 8 位字体,但由于不知道您的要求,我无法告诉您这是否适合您。

相关内容